跳表是一个很有意思的数据结构,它实现简单,但是性能又可以和平衡二叉搜索树差不多。

据MIT公开课上教授的讲解,它的想法和纽约地铁有异曲同工之妙,简而言之就是不断地增加“快线”,从而降低时间复杂度。

当“快线”的数量为lgn时,我们就得到了现在的快表——一个类似于平衡二叉搜索树的数据结构。

网上没有比较标准的实现方案,CLRS中也没有给出伪代码。(可能是因为他们觉得太容易实现了...)所以我给出是一个完全由我自己根据快表性质写的一个版本,如果大家有更好的实现版本欢迎和我分享。

增加层数的方案用的是抛硬币,即根据随机数来确定是否增加“快线”,这也是MIT公开课上给出的一个比较简单的实现方法。

代码如下:(仅供参考)

 class Skiplist {
private :
struct Node {
int key;
Node * prev;
Node * next;
Node * down;
Node * top;
Node() : key(), prev(nullptr), next(nullptr), down(nullptr), top(nullptr) {}
};
private :
Node * head;
int level;
int size;
private :
void bindNewNode(Node * x, Node * p);
void delNode(Node * x);
Node * searchNode(int key);
public :
Skiplist() : head(new Node), level(),size()
{head->key = INT_MIN; srand(static_cast<int>(time()));}
~Skiplist() {delete head;}
void insert(int key);
void remove(int key);
bool search(int key) {return (searchNode(key) != nullptr);}
void showSkiplist();
int getLevel() {return level;}
int getSize() {return size;}
}; void Skiplist::bindNewNode(Node * x, Node * p) {
if (!x->next) {
x->next = p;
p->prev = x;
}
else {
p->next = x->next;
x->next->prev = p;
p->prev = x;
x->next = p;
}
} void Skiplist::insert(int key) {
Node * p = new Node;
p->key = key; Node * x = head;
while () { //find the prev node of p, which represents the right insert place
if (x->key <= key) {
if (x->next)
x = x->next;
else if (x->down)
x = x->down;
else break;
}
else if (x->prev->down)
x = x->prev->down;
else {
x = x->prev;
break;
}
}
bindNewNode(x, p);
while (rand() % ) { //throw the coin, then judge whether it needs to be higher according to the results
Node * highp = new Node;
highp->key = key;
while (!x->top && x->prev)
x = x->prev;
if (x->top) {
x = x->top;
bindNewNode(x, highp);
highp->down = p;
p->top = highp;
}
else { //already the top, add a sentry
Node * top = new Node;
x = top;
top->key = INT_MIN;
top->down = head;
head->top = top;
head = top;
bindNewNode(top, highp);
highp->down = p;
p->top = highp;
++level;
}
p = highp;
}
++size;
} void Skiplist::delNode(Node * x) {
if (!x->next) { //node x is the last one
if (x->prev == head && head->down) { //x is not at the bottom and x is the last one of this level
head = head->down;
head->top = nullptr;
delete x->prev;
--level;
}
else
x->prev->next = nullptr;
}
else {
x->prev->next = x->next;
x->next->prev = x->prev;
}
delete x;
} void Skiplist::remove(int key) {
Node * x = searchNode(key);
if (x) {
while (x->down) {
Node * y = x->down;
delNode(x);
x = y;
}
delNode(x);
--size;
}
} Skiplist::Node * Skiplist::searchNode(int key) {
Node * x = head;
while () { //find the prev node of p, which represents the right insert place
if (x->key == key)
return x;
else if (x->key < key) {
if (x->next)
x = x->next;
else if (x->down)
x = x->down;
else
return nullptr;
}
else if (x->prev->down)
x = x->prev->down;
else {
return nullptr;
}
}
} void Skiplist::showSkiplist() {
Node * x = head, * y = head;
while (y) {
x = y;
while (x) {
if (x->prev != nullptr)
cout << x->key << ' ';
x = x->next;
}
cout << endl;
y = y->down;
}
}

skip-list(跳表)原理及C++代码实现的更多相关文章

  1. 聊聊Mysql索引和redis跳表 ---redis的有序集合zset数据结构底层采用了跳表原理 时间复杂度O(logn)(阿里)

    redis使用跳表不用B+数的原因是:redis是内存数据库,而B+树纯粹是为了mysql这种IO数据库准备的.B+树的每个节点的数量都是一个mysql分区页的大小(阿里面试) 还有个几个姊妹篇:介绍 ...

  2. JAVA SkipList 跳表 的原理和使用例子

    跳跃表是一种随机化数据结构,基于并联的链表,其效率可比拟于二叉查找树(对于大多数操作需要O(log n)平均时间),并且对并发算法友好. 关于跳跃表的具体介绍可以参考MIT的公开课:跳跃表 跳跃表的应 ...

  3. skip list跳跃表实现

    跳表(skip List)是一种随机化的数据结构,基于并联的链表,实现简单,插入.删除.查找的复杂度均为O(logN).跳表的具体定义,跳表是由William Pugh发明的,这位确实是个大牛,搞出一 ...

  4. 自己动手实现java数据结构(九) 跳表

    1. 跳表介绍 在之前关于数据结构的博客中已经介绍过两种最基础的数据结构:基于连续内存空间的向量(线性表)和基于链式节点结构的链表. 有序的向量可以通过二分查找以logn对数复杂度完成随机查找,但由于 ...

  5. levelDB跳表实现

    跳表的原理就是利用随机性建立索引,加速搜索,并且简化代码实现难度.具体的跳表原理不再赘述,主要是看了levelDB有一些实现细节的东西,凸显自己写的实现不足之处. 去除冗余的key template& ...

  6. 3.3.7 跳表 SkipList

    一.前言 concurrentHashMap与ConcurrentSkipListMap性能测试 在4线程1.6万数据的条件下,ConcurrentHashMap 存取速度是ConcurrentSki ...

  7. C语言跳表(skiplist)实现

    一.简介 跳表(skiplist)是一个非常优秀的数据结构,实现简单,插入.删除.查找的复杂度均为O(logN).LevelDB的核心数据结构是用跳表实现的,redis的sorted set数据结构也 ...

  8. redis为何单线程 效率还这么高 为何使用跳表不使用B+树做索引(阿里)

    如果想了解 redis 与Memcache的区别参考:Redis和Memcache的区别总结 阿里的面试官问问我为何redis 使用跳表做索引,却不是用B+树做索引 因为B+树的原理是 叶子节点存储数 ...

  9. skiplist(跳表)的原理及JAVA实现

    前记 最近在看Redis,之间就尝试用sortedSet用在实现排行榜的项目,那么sortedSet底层是什么结构呢? "Redis sorted set的内部使用HashMap和跳跃表(S ...

随机推荐

  1. 用Python读取一个文本文件并统计词频

    刚刚在写文章时360浏览器崩溃了,结果内容还是找回来了,感谢博客园的自动保存功能!!! ------------恢复内容开始------------ 最近在学习Python,自己写了一个小程序,可以从 ...

  2. PTA 天梯赛 L1

    L1-002 打印沙漏 细节:就是在  (i>j&&i+j<r+1) 这个区间里才有空格,然后就是 for 循环   for(r=1; ;r+=2)  条件不满足之后还会再 ...

  3. 一个例子搞清楚Java程序执行顺序

    当我们new一个GirlFriend时,我们都做了什么? 一个例子搞懂Java程序运行顺序 public class Girl { Person person = new Person("G ...

  4. dd if= of= MBR

    1.备份分区表信息 sudo fdisk -l >hda.txt  #分区表信息重定向输出到文件中 2.备份MBR sudo dd if=/dev/sda of=mbr bs=512 count ...

  5. mac item2自定义光标移动快捷键,移动行首行尾,按单词跳转

    To jump between words and start/end of lines in iTerm2 follow these steps: iTerm2 -> Preferences ...

  6. sping中 各种注解——@SuppressWarnings注解用法

    @SuppressWarnings注解用法 @SuppressWarnings注解主要用在取消一些编译器产生的警告对代码左侧行列的遮挡,有时候这会挡住我们断点调试时打的断点. 如图所示: 这时候我们在 ...

  7. poj 3013 最短路SPFA算法

    POJ_3013_最短路 Big Christmas Tree Time Limit: 3000MS   Memory Limit: 131072K Total Submissions: 23630 ...

  8. uwsgi Import Error: No module named 'encodings'

    https://serverfault.com/questions/558427/uwsgi-import-error-no-module-named-encodings I don't know i ...

  9. ThreeJS 阴影条纹BUG

    ThreeJS 开启阴影正确做法: 1. 渲染器启用阴影 renderer.shadowMap.enabled = true;2. 灯光产生阴影 light.castShadow = true;3. ...

  10. Ubuntu---不能打开 exfat 文件系统格式的 U盘解决方法

    出现问题:今天把 U 盘插入 Ubuntu 系统的电脑中,打开 U 盘发现弹出 系统格式不支持 的提醒,无法进入 U 盘进行操作. 环境: Ubuntu18.04 TSL; 格式化为 exfat 文件 ...