当前位置: 代码迷 >> 综合 >> 跳表 SkipList 实现
  详细解决方案

跳表 SkipList 实现

热度:79   发布时间:2024-01-14 08:16:29.0
skiplist

最近发现很多kv都使用到了skiplist,所以自己也就实现一个skipList.
它的特点

  1. 平衡时变动小,不像红黑树可能插入一个新节点可能影响从它开始上溯到的所有节点。比如现在插入一个子节点,局部影响的就是父亲节点、叔叔节点、爷爷节点,此时可能发生旋转但是局部的平衡后,可能爷爷节点的颜色会改变,导致爷爷的局部不平衡,所以可能引起上溯的所有节点可能都需要发生相应的变化,所以并发情况下红黑树并不是首选。
  2. 内部跟红黑树一样都是有序的,红黑树中序遍历的结果key值都是有序的,相同跳表的第1层链包含了所有的元素,直接遍历这条链的结果也都是有序的
  3. 跳表每个节点插入的层数由随机数定,比如每次有1/4的概率往上一层插入,那么每个节点的层高概率为 (1/4)^n-1 ,这样就造成高层的节点远小于底层的节点从而加快遍历速度。
  4. 平均时间复杂度 logn
  5. Cur 节点的Key值 比 Prev节点的Key值大,比Next节点Key值小。(升序情况)
图示讲解

下面这个图就是一个跳表,跳表每个节点分为俩部分,一部分是数据Key,一部分是下一个节点的索引数组。从下面的图可以看到,有的层数1,有的层数2,这个就说明3,11,22,37是层数为1的时候插入到跳表的。7,19,26是层数为2的时候插入到跳表的。
从下面可以看到跳表是有序的。一般find是从最高层开始查找,如果最高层找到了Target就直接返回,如果找不到就去下一层找。
在这里插入图片描述

插入列图
代码实现
#ifndef STUDY_LEVELDB_SKIP_LIST_H
#define STUDY_LEVELDB_SKIP_LIST_H
#define NULL 0
#include "random.h"
#include <stdlib.h>class Random;class AtomicPointer {public:AtomicPointer(void* rep):rep_(rep){}AtomicPointer():rep_(NULL){}void Store(void* p) {__asm__ __volatile__("" : : : "memory");rep_ = p;}void* Load() {void* result = rep_;__asm__ __volatile__("" : : : "memory");return result;}private:void* rep_;
};template<typename Key>
class SkipList 
{private:struct SkipNode;public:SkipList() :maxlevel_(reinterpret_cast<void*>(1)),head_(NewNode(Key(), kMaxLevel)){for(int32_t i = 0; i < kMaxLevel; ++i) {head_[i].SetNext(i,NULL);}}void Insert(const Key& key);bool Find(const Key& key);private:enum { kMaxLevel = 12 };#if 0SkipNode* NewNode(const Key& key, int maxlevel) {void* ptr = malloc(sizeof(SkipNode) + (maxlevel-1)*sizeof(AtomicPointer));return new (ptr) SkipNode<Key>(key);}
#endifSkipNode* NewNode(const Key& key, int maxlevel);SkipNode* FindGreaterOrEqual(const Key& key, SkipNode** prev);bool CompareLessKey(const SkipNode* node, const Key& key);int GetMaxLevel() {return reinterpret_cast<long int>(maxlevel_.Load());}//1/4 的insert会提高层数int RandomLevel() {int maxlevel = 1;while(maxlevel < kMaxLevel && rnd_.rand_int(1,4) == 0) {maxlevel++;}return maxlevel;}private:AtomicPointer maxlevel_;SkipNode* head_;global_random rnd_;
};template<typename Key>
struct SkipList<Key>::SkipNode {public:Key const key_;SkipNode(const Key& key):key_(key){}void SetNext(int level, SkipNode* ptr) {next[level].Store(ptr);}SkipNode* GetNext(int level) {return reinterpret_cast<SkipNode*>(next[level].Load());}private:AtomicPointer next[1];
};template<typename Key>
typename SkipList<Key>::SkipNode* 
SkipList<Key>::NewNode(const Key& key, int maxlevel) {void* ptr = malloc(sizeof(SkipNode) + (maxlevel-1)*sizeof(AtomicPointer));return new (ptr) SkipNode(key);
}template<typename Key>
bool SkipList<Key>::CompareLessKey(const SkipNode* node, const Key& key) {return node!=NULL && node->key_<key;
}//该函数不是找到key的节点,而是找到刚好Key值大于等于 key的节点的所有prev节点
template<typename Key>
typename SkipList<Key>::SkipNode* SkipList<Key>::FindGreaterOrEqual(const Key& key, SkipNode** prev_array) {int level = GetMaxLevel()-1;SkipNode* prev = head_;SkipNode* cur  = NULL;while(true) {cur = prev->GetNext(level);//找到节点的 level链表的第一个节点if(CompareLessKey(cur, key)) {//说明key 大于 node->keyprev = cur;} else {if(prev_array!= NULL) {prev_array[level] = prev;}if(level == 0) {break;}level--; //key < node->key 从更低一级的链表查找}}return cur;
}template<typename Key>
void SkipList<Key>::Insert(const Key& key) {typename SkipList<Key>::SkipNode* prev[kMaxLevel];SkipNode* next = FindGreaterOrEqual(key, prev); //找到从 0 ~ maxlevel_ 层(当前最高层)中该节点的prev节点if(next != NULL && next->key_ == key) {return ;}int node_max_level = RandomLevel();int max_level = GetMaxLevel();if(node_max_level > max_level) {//说明这次随机出来的层数比之前最高层高 for(int i = node_max_level-1; i >= max_level; ++i) {prev[i] = head_;}maxlevel_.Store(reinterpret_cast<void*>(max_level)); }//构造NewNodeSkipNode* node = NewNode(key, node_max_level);//插入该node到SkipList中//设置好0 ~ NodeMaxLevel 对应层的next节点与prev节点for(int i = 0; i < node_max_level; ++i) {node->SetNext(i, prev[i]->GetNext(i)); //设置好第i层的next节点prev[i]->SetNext(i, node);}
}template<typename Key>  
bool SkipList<Key>::Find(const Key& key) {SkipNode* next = FindGreaterOrEqual(key, NULL);return next!=NULL && next->key_ == key;
}#endif //STUDY_LEVELDB_SKIP_LIST_H
单元测试
#include "skip_list.h"
#include <gtest/gtest.h>TEST(TestSkipList,TestInsert) 
{SkipList<int> skplist;skplist.Insert(1);EXPECT_TRUE(skplist.Find(1));
}int main(int argc, char** argv)
{testing::InitGoogleTest(&argc, argv);return RUN_ALL_TESTS();
}