跳表(Skip List)是一种数据结构,可以用来实现有序的键值对集合,并且支持快速的插入、删除和查找操作。它类似于平衡树,但是更简单,并且在很多情况下性能更好。
跳表由多层链表组成,每一层链表都是原始链表的一个子集,每一层都按照键值进行排序。最底层包含所有的元素,而顶层包含最少的元素,可以视为一个加速器,用于快速定位到底层链表中的元素。
在 C++ 中实现跳表需要设计节点类和跳表类,以及一些辅助函数来支持插入、删除和查找操作。以下是一个简单的跳表的示例实现:
#include <iostream>
#include <cstdlib> // 用于随机数生成
#include <ctime> // 用于设置随机数种子
// 跳表节点类
template<typename K, typename V>
struct SkipListNode {
K key;
V value;
SkipListNode** forward;
SkipListNode(K k, V v, int level) : key(k), value(v) {
forward = new SkipListNode*[level + 1];
for (int i = 0; i <= level; ++i) {
forward[i] = nullptr;
}
}
~SkipListNode() {
delete[] forward;
}
};
// 跳表类
template<typename K, typename V>
class SkipList {
private:
int MAX_LEVEL;
float P;
int level;
SkipListNode<K, V>* header;
public:
SkipList(int max_level, float p) : MAX_LEVEL(max_level), P(p), level(0) {
header = new SkipListNode<K, V>(K(), V(), MAX_LEVEL);
srand(time(NULL));
}
~SkipList() {
delete header;
}
// 随机生成一个层数
int randomLevel() {
int level = 0;
while (level < MAX_LEVEL && (float)rand() / RAND_MAX < P) {
level++;
}
return level;
}
// 插入键值对
void insert(K key, V value) {
SkipListNode<K, V>* update[MAX_LEVEL + 1];
SkipListNode<K, V>* current = header;
for (int i = level; i >= 0; --i) {
while (current->forward[i] != nullptr && current->forward[i]->key < key) {
current = current->forward[i];
}
update[i] = current;
}
current = current->forward[0];
if (current == nullptr || current->key != key) {
int newLevel = randomLevel();
if (newLevel > level) {
for (int i = level + 1; i <= newLevel; ++i) {
update[i] = header;
}
level = newLevel;
}
current = new SkipListNode<K, V>(key, value, newLevel);
for (int i = 0; i <= newLevel; ++i) {
current->forward[i] = update[i]->forward[i];
update[i]->forward[i] = current;
}
}
}
// 查找键对应的值
V find(K key) {
SkipListNode<K, V>* current = header;
for (int i = level; i >= 0; --i) {
while (current->forward[i] != nullptr && current->forward[i]->key < key) {
current = current->forward[i];
}
}
current = current->forward[0];
if (current != nullptr && current->key == key) {
return current->value;
} else {
return V(); // 返回默认值
}
}
// 删除键值对
void erase(K key) {
SkipListNode<K, V>* update[MAX_LEVEL + 1];
SkipListNode<K, V>* current = header;
for (int i = level; i >= 0; --i) {
while (current->forward[i] != nullptr && current->forward[i]->key < key) {
current = current->forward[i];
}
update[i] = current;
}
current = current->forward[0];
if (current != nullptr && current->key == key) {
for (int i = 0; i <= level; ++i) {
if (update[i]->forward[i] != current) break;
update[i]->forward[i] = current->forward[i];
}
delete current;
while (level > 0 && header->forward[level] == nullptr) {
level--;
}
}
}
};
int main() {
// 创建一个跳表
SkipList<int, std::string> skipList(4, 0.5);
// 插入一些键值对
skipList.insert(1, "One");
skipList.insert(2, "Two");
skipList.insert(3, "Three");
skipList.insert(4, "Four");
skipList.insert(5, "Five");
// 查找键对应的值并输出
std::cout << "Value for key 3: " << skipList.find(3) << std::endl;
// 删除键值对
skipList.erase(3);
// 再次查找键对应的值并输出
std::cout << "Value for key 3 after deletion: " << skipList.find(3) << std::endl;
return 0;
}
在这个示例中,我们定义了一个 SkipListNode 类来表示跳表的节点,包含键、值以及一个指向下一个节点的指针数组。然后,定义了一个 SkipList 类来实现跳表,提供了插入、查找和删除等操作。在 main 函数中,我们创建了一个跳表对象,并插入了一些键值对,然后查找了一个键的值,并进行了删除操作。