跳表通过多层链表实现快速查找,C++中以随机层级和指针数组构建,支持高效插入、删除与搜索,平均时间复杂度O(log n),代码简洁但需注意线程安全。
跳表(Skip List)是一种基于概率的动态数据结构,用来快速查找、插入和删除元素,平均时间复杂度为 O(log n)。相比平衡树,跳表实现更简单,同时具备良好的性能。在C++中实现跳表,需要理解其层级链表结构和随机层级生成机制。
跳表通过多层链表实现快速跳跃访问:
每个节点包含多个向右指针,层数在创建时随机决定:
templateclass SkipListNode { public: K key; V value; std::vector forward; SkipListNode(K k, V v, int level) : key(k), value(v), forward(level, nullptr) {}};
说明: forward 是一个指针数组,forward[i] 指向第 i 层的下一个节点。
实现核心操作:查找、插入、删除、层级生成等:
templateclass SkipList { private: static const int MAX_LEVEL = 16; int currentLevel; SkipListNode * header; int randomLevel(); void displayList();public: SkipList(); ~SkipList();
SkipListNodezuojiankuohaophpcnK,Vyoujiankuohaophpcn* search(K key); void insert(K key, V value); void remove(K key); void display();};
关键成员解释:
使用随机数决定新节点应有多少层:
templateint SkipList ::randomLevel() { int level = 1; while (rand() % 2 && level < MAX_LEVEL) { level++; } return level; }
说明: 每次有50%的概率继续向上加一层,直到达到最大限制。
从顶层开始,向右走到底再往下走:
templateSkipListNode * SkipList ::search(K key) { SkipListNode * curr = header; for (int i = currentLevel; i >= 1; i--) { while (curr->forward[i] && curr->forward[i]->key < key) { curr = curr->forward[i]; } } curr = curr->forward[1]; if (curr && curr->key == key) { return curr; } return nullptr; }
先搜索路径记录每层最后到达的节点,再逐层更新指针:
templatevoid SkipList ::insert(K key, V value) { std::vector *> update(MAX_LEVEL + 1, nullptr); SkipListNode * curr = header; for (int i = currentLevel; i youjiankuohaophpcn= 1; i--) { while (curr-youjiankuohaophpcnforward[i] && curr-youjiankuohaophpcnforward[i]-youjiankuohaophpcnkey zuojiankuohaophpcn key) { curr = curr-youjiankuohaophpcnforward[i]; } update[i] = curr; } curr = curr-youjiankuohaophpcnforward[1]; if (curr && curr-youjiankuohaophpcnkey == key) { curr-youjiankuohaophpcnvalue = value; return; } int newLevel = randomLevel(); if (newLevel youjiankuohaophpcn currentLevel) { for (int i = currentLevel + 1; i zuojiankuohaophpcn= newLevel; i++) { update[i] = header; } currentLevel = newLevel; } SkipListNodezuojiankuohaophpcnK,Vyoujiankuohaophpcn* newNode = new SkipListNodezuojiankuohaophpcnK,Vyoujiankuohaophpcn(key, value, newLevel); for (int i = 1; i zuojiankuohaophpcn= newLevel; i++) { newNode-youjiankuohaophpcnforward[i] = update[i]-youjiankuohaophpcnforward[i]; update[i]-youjiankuohaophpcnforward[i] = newNode; }}
找到节点后,将其从各层链表中移除,并清理空层:
templatevoid SkipList ::remove(K key) { std::vector *> update(MAX_LEVEL + 1, nullptr); SkipListNode * curr = header; for (int i = currentLevel; i youjiankuohaophpcn= 1; i--) { while (curr-youjiankuohaophpcnforward[i] && curr-youjiankuohaophpcnforward[i]-youjiankuohaophpcnkey zuojiankuohaophpcn key) { curr = curr-youjiankuohaophpcnforward[i]; } update[i] = curr; } curr = curr-youjiankuohaophpcnforward[1]; if (!curr || curr-youjiankuohaophpcnkey != key) return; for (int i = 1; i zuojiankuohaophpcn= currentLevel; i++) { if (update[i]-youjiankuohaophpcnforward[i] != curr) break; update[i]-youjiankuohaophpcnforward[i] = curr-youjiankuohaophpcnforward[i]; } delete curr; while (currentLevel youjiankuohaophpcn 1 && header-youjiankuohaophpcnforward[currentLevel] == nullptr) {currentLevel--; }
}
初始化头节点并释放内存:
templateSkipList ::SkipList() : currentLevel(1) { header = new SkipListNode (K(), V(), MAX_LEVEL); } template
SkipList ::~SkipList() { SkipListNode curr = header->forward[1]; while (curr) { SkipListNode next = curr->forward[1]; delete curr; curr = next; } delete header; }
便于调试,显示每层节点:
templatevoid SkipList ::display() { for (int i = currentLevel; i >= 1; i--) { SkipListNode * node = header->forward[i]; std::cout << "Level " << i << ": "; while (node) { std::cout << node->key << "(" << node->value << ") "; node = node->forward[i]; } std::cout << std::endl; } }
基本上就这些。C++实现跳表的关键在于管理多级指针和维护搜索路径。虽然不如STL中的set/map底层高效(红黑树或B+树),但跳表代码清晰、易于扩展(如支持范围查询、计数等),适合学习和特定场景使用。注意线程安全问题,若需并发访问,应添加锁机制。