用跳表实现 C++ 中的 std::map 数据结构

57 阅读2分钟

跳表(Skip List)是一种基于有序链表的数据结构,它通过在原始链表上建立多层索引链表来加速查找操作。每一层的链表都是原始链表的一个子集,同时层与层之间的元素是逐渐稀疏的。跳表的平均时间复杂度为 O(log n),并且不需要像平衡树那样复杂的平衡操作,因此在实践中是一种高效的数据结构。

要用跳表实现一个类似于 C++ 中的 std::map 的数据结构,可以考虑以下步骤:

  1. 定义跳表节点结构:每个节点包含一个键值对,以及指向下一个节点的指针数组。
  2. 定义跳表类:实现插入、删除、查找等基本操作。
  3. 实现类似于 std::map 的功能:例如插入键值对、根据键查找值、删除键值对等。

以下是一个简单的 C++ 实现示例:

#include <cstdlib>
#include <ctime>
#include <iostream>
#include <vector>
#include <map>

const int MAX_LEVEL = 16;

template<typename K, typename V>
struct SkipListNode {
    K key;
    V value;
    std::vector<SkipListNode<K, V>*> forwards;

    SkipListNode(K k, V v, int level) : key(k), value(v), forwards(level, nullptr) {}
};

template<typename K, typename V>
class SkipListMap {
private:
    SkipListNode<K, V>* head;
    int level;
    int size;

public:
    SkipListMap() : level(1), size(0) {
        head = new SkipListNode<K, V>(K(), V(), MAX_LEVEL);
    }

    ~SkipListMap() {
        SkipListNode<K, V>* node = head->forwards[0];
        while (node != nullptr) {
            SkipListNode<K, V>* tmp = node->forwards[0];
            delete node;
            node = tmp;
        }
        delete head;
    }

    void insert(const K& key, const V& value) {
        std::vector<SkipListNode<K, V>*> update(MAX_LEVEL, nullptr);
        SkipListNode<K, V>* node = head;
        for (int i = level - 1; i >= 0; --i) {
            while (node->forwards[i] != nullptr && node->forwards[i]->key < key) {
                node = node->forwards[i];
            }
            update[i] = node;
        }
        node = node->forwards[0];
        if (node != nullptr && node->key == key) {
            node->value = value;
        } else {
            int newLevel = randomLevel();
            if (newLevel > level) {
                for (int i = level; i < newLevel; ++i) {
                    update[i] = head;
                }
                level = newLevel;
            }
            node = new SkipListNode<K, V>(key, value, newLevel);
            for (int i = 0; i < newLevel; ++i) {
                node->forwards[i] = update[i]->forwards[i];
                update[i]->forwards[i] = node;
            }
            ++size;
        }
    }

    V* search(const K& key) const {
        SkipListNode<K, V>* node = head;
        for (int i = level - 1; i >= 0; --i) {
            while (node->forwards[i] != nullptr && node->forwards[i]->key < key) {
                node = node->forwards[i];
            }
        }
        node = node->forwards[0];
        if (node != nullptr && node->key == key) {
            return &(node->value);
        } else {
            return nullptr;
        }
    }

    void erase(const K& key) {
        std::vector<SkipListNode<K, V>*> update(MAX_LEVEL, nullptr);
        SkipListNode<K, V>* node = head;
        for (int i = level - 1; i >= 0; --i) {
            while (node->forwards[i] != nullptr && node->forwards[i]->key < key) {
                node = node->forwards[i];
            }
            update[i] = node;
        }
        node = node->forwards[0];
        if (node != nullptr && node->key == key) {
            for (int i = 0; i < level; ++i) {
                if (update[i]->forwards[i] == node) {
                    update[i]->forwards[i] = node->forwards[i];
                }
            }
            delete node;
            while (level > 1 && head->forwards[level - 1] == nullptr) {
                --level;
            }
            --size;
        }
    }

    int randomLevel() {
        int level = 1;
        while (rand() % 2 == 0 && level < MAX_LEVEL) {
            ++level;
        }
        return level;
    }

    int getSize() const {
        return size;
    }
};

int main() {
    srand(time(nullptr));
    
    // 使用跳表实现的类似于 std::map 的数据结构
    SkipListMap<int, std::string> skipListMap;

    // 插入键值对
    skipListMap.insert(1, "One");
    skipListMap.insert(2, "Two");
    skipListMap.insert(3, "Three");

    // 查找键值对
    std::cout << "Value of key 2: " << *(skipListMap.search(2)) << std::endl;

    // 删除键值对
    skipListMap.erase(2);

    // 再次查找键值对
    std::cout << "Value of key 2 after deletion: " << (skipListMap.search(2) ? *(skipListMap.search(2)) : "Not found") << std::endl;

    return 0;
}

这个示例演示了如何用跳表实现一个类似于 std::map 的数据结构。它包括跳表节点结构 SkipListNode 和跳表类 SkipListMap,以及 main 函数中的示例用法。