c++实现跳表

353 阅读2分钟

跳表(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 函数中,我们创建了一个跳表对象,并插入了一些键值对,然后查找了一个键的值,并进行了删除操作。