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)
通过该接口串联起 增-删-查的逻辑