C++实现的简单跳表(SkipList)

C++实现的简单跳表(SkipList)

#pragma once
#include <vector>
#include <array>
#include <memory>
template <class K, class V>
struct SkipListNode
{
    SkipListNode(size_t nLevel) : Level(nLevel),
                                  arrlpNext(nLevel, nullptr)
    {
        ;
    }
    K Key = {};
    V Val = {};
    size_t Level;                          // 当前节点层数
    std::vector<SkipListNode *> arrlpNext; // next指针数组
};

// 由小到大
template <class K, class V, size_t LEVEL = 20>
class SkipList
{
    using Node = SkipListNode<K, V>;
    using PreNode = std::array<SkipListNode<K, V> *, LEVEL>;

public:
    SkipList() : m_DummyNode(LEVEL)
    {
        ;
    }
    ~SkipList()
    {
        Node* lpCurr = m_DummyNode.arrlpNext[0];
        while (lpCurr)
        {
            Node *lpTmp = lpCurr;
            lpCurr = lpCurr->arrlpNext[0];
            _ReleaseNode(lpTmp);
        }
    }

public:
    bool Insert(const K &refKey, const V &refVal)
    {
        PreNode preNode = {};
        if (nullptr != _Find(refKey, &preNode))
        {
            return false;
        }

        Node *lpNode = _CreateNode(_GetLevel());
        if (nullptr == lpNode)
        {
            return false;
        }

        lpNode->Key = refKey;
        lpNode->Val = refVal;

        // 将preNode的next指向当前节点
        for (size_t i = 0; i < lpNode->Level; ++i)
        {
            // 当前节点next = 前一个节点next
            lpNode->arrlpNext[i] = preNode[i]->arrlpNext[i];
            // 前一个节点next指向当前节点
            preNode[i]->arrlpNext[i] = lpNode;
        }
        return true;
    }

    V *Find(const K &refKey)
    {
        Node *lpRtn = _Find(refKey);
        if(lpRtn)
        {
            return &lpRtn->Val;
        }
        return nullptr;
    }

    bool Erase(const K &refKey)
    {
        PreNode preNode = {};
        Node *lpCurr = _Find(refKey, &preNode);
        if (nullptr == lpCurr)
        {
            return false;
        }

        // 将前一个节点的next指向当前节点的next
        for (size_t i = 0; i < lpCurr->Level; ++i)
        {
            preNode[i]->arrlpNext[i] = lpCurr->arrlpNext[i];
        }
        
        _ReleaseNode(lpCurr);
        
        return true;
    }

private:
    // 查找对应节点
    Node *_Find(const K &refKey, PreNode *lpPreNode = nullptr)
    {
        Node *lpCurr = &m_DummyNode;
        // 把每层当作一个独立的链表查找,如果找不到则转移到下一层
        for (int i = LEVEL - 1; i >= 0; --i)
        {
            // 循环当前层的链表 找到小于key的最远端
            while (lpCurr->arrlpNext[i] != nullptr && lpCurr->arrlpNext[i]->Key < refKey)
            {
                lpCurr = lpCurr->arrlpNext[i];
            }
            // 退出循环表示找到了前一个节点
            if (lpPreNode != nullptr)
            {
                (*lpPreNode)[i] = lpCurr;
            }
        }

        // 当前节点置为最底层的next
        lpCurr = lpCurr->arrlpNext[0];

        if (lpCurr != nullptr && lpCurr->Key == refKey)
        {
            return lpCurr;
        }
        return nullptr;
    }

    // 获取随机层数
    size_t _GetLevel()
    {
        size_t level = 1;
        while ((random() & 0xFFFF) < (0.25 * 0xFFFF))
            level += 1;
        return (level < LEVEL) ? level : LEVEL;
    }

    // 创建一个节点
    Node *_CreateNode(size_t nLevel)
    {
        return new Node(nLevel);
    }

    // 释放一个节点
    void _ReleaseNode(Node * lpNode)
    {
        if (lpNode)
        {
            delete lpNode;
        }
    }

private:
    Node m_DummyNode = {};
};

重点函数为

 Node *_Find(const K &refKey, PreNode *lpPreNode = nullptr)

通过该接口串联起 增-删-查的逻辑

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值