SkipList算法实现
SkipList是一种快速查找链表,链表元素的是有序的。由W.Pugh发明于1989年。
其算法复杂度如下:
Average Worst case
Space O(n) O(n log n)
Search O(log n) O(n)
Insert O(log n) O(n)
Delete O(log n) O(n)

(图片来源于WiKi)
均算法复杂度不亚于AVL和红黑树。其数据结构和操作也简单。AVL树和红黑树为保
持平衡,维护树的平衡代价高。
SkipList 现用于Redis,LevelDB等开源项目, 维基百科可以看它到很多应用场景。
根据W.Pugh的论文,其算法实现如下:
#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <random>
using namespace std; #define MaxLevel 5 typedef struct SkipListNode {
int value;
int key;
int level;
SkipListNode* forward[MaxLevel];
} SkipListNode; typedef struct SkipList {
SkipListNode* head;
int level;
int length;
} SkipList; SkipListNode* makeNode(int level, int key, int value)
{
SkipListNode* pNode = (SkipListNode *)malloc(sizeof(SkipListNode));
if (!pNode) {
return NULL;
}
pNode->key = key;
pNode->value = value;
pNode->level = level;
for (int i = ; i < MaxLevel; ++i)
pNode->forward[i] = NULL; return pNode;
} void initSkipList(SkipList *pSkipList)
{
if (!pSkipList)
return;
SkipListNode* head = makeNode(, , );
if (!head)
return;
pSkipList->head = head;
pSkipList->length = ;
pSkipList->level = ; for (int i = ; i < MaxLevel; i++)
pSkipList->head->forward[i] = NULL;
} int randomLevel()
{
int newLevel = ;
while ((rand() & 0xFFFF) < (0.4 * 0xFFFF))
++newLevel;
return newLevel < MaxLevel ? newLevel : MaxLevel;
}
bool insertNode(SkipList *pSkipList, int searchKey, int newValue)
{
SkipListNode* update[MaxLevel];
if (!pSkipList)
return false; SkipListNode* pNode = pSkipList->head;
if (!pNode) {
return false;
}
for (int i = pSkipList->level - ; i >= ; i--) {
while (pNode->forward[i] && pNode->forward[i]->key < searchKey)
pNode = pNode->forward[i]; // pNode->key < searchKey < pNode->forward[i]->key
update[i] = pNode;
}
pNode = pNode->forward[];
if (pNode && pNode->key == searchKey) {
pNode->value = newValue;
}
else {
int level = randomLevel();
if (level > pSkipList->level) {
for (int i = pSkipList->level; i < level; i++) {
update[i] = pSkipList->head;
}
pSkipList->level = level;
}
pNode = makeNode(level, searchKey, newValue);
if (!pNode) {
return false;
}
for (int i = ; i < pSkipList->level; ++i) {
pNode->forward[i] = update[i]->forward[i];
update[i]->forward[i] = pNode;
}
pSkipList->length++;
}
return true;
} SkipListNode* searchNode(SkipList *pSkipList, int searchKey) {
if (!pSkipList)
return NULL; SkipListNode *pNode = pSkipList->head;
if (!pNode)
return NULL; for (int i = pSkipList->level - ; i >= ; --i) {
while (pNode->forward[i] && pNode->forward[i]->key < searchKey)
pNode = pNode->forward[i];
} pNode = pNode->forward[];
if (pNode && pNode->key == searchKey)
return pNode;
return NULL;
} bool deleteNode(SkipList* pSkipList, int searchKey) {
if (!pSkipList)
return false; SkipListNode *pNode = pSkipList->head;
SkipListNode *update[MaxLevel]; for (int i = pSkipList->level - ; i >= ; i--) {
while (pNode->forward[i] && pNode->forward[i]->key < searchKey) {
pNode = pNode->forward[i];
}
update[i] = pNode;
} pNode = pNode->forward[];
if (pNode && pNode->key == searchKey) {
for (int i = ; i < pSkipList->level; ++i) {
if (update[i] && update[i]->forward[i] != pNode) {
break;
}
update[i]->forward[i] = pNode->forward[i];
}
free(pNode);
while (pSkipList->level > &&
pSkipList->head->forward[pSkipList->level - ] == NULL) {
pSkipList->level--;
}
pSkipList->length--;
return true;
}
return false;
} void travelList(SkipList* pSkipList)
{
SkipListNode* pNode = pSkipList->head;
if (!pNode)
return; while (pNode->forward[]) {
cout << pNode->forward[]->value << " " << pNode->forward[]->level << endl;
pNode = pNode->forward[];
}
} int main()
{
SkipList list;
initSkipList(&list); insertNode(&list, , );
insertNode(&list, , );
insertNode(&list, , ); travelList(&list); SkipListNode* pNode = searchNode(&list, );
cout << pNode->value << endl; pNode = searchNode(&list, );
cout << pNode->value << endl; cout << "----" << endl;
deleteNode(&list, );
travelList(&list); cout << "----" << endl;
deleteNode(&list, );
travelList(&list); cout << "----" << endl;
deleteNode(&list, );
travelList(&list);
return ;
}
SkipList算法实现的更多相关文章
- 深夜学算法之SkipList:让链表飞
1. 前言 上次写Python操作LevelDB时提到过,有机会要实现下SkipList.摘录下wiki介绍: 跳跃列表是一种随机化数据结构,基于并联的链表,其效率可比拟二叉查找树. 我们知道对于有序 ...
- 算法: skiplist 跳跃表代码实现和原理
SkipList在leveldb以及lucence中都广为使用,是比较高效的数据结构.由于它的代码以及原理实现的简单性,更为人们所接受. 所有操作均从上向下逐层查找,越上层一次next操作跨度越大.其 ...
- ssdb底层实现——ssdb底层是leveldb,leveldb根本上是skiplist(例如为存储多个list items,必然有多个item key,而非暴力string cat),用它来做redis的list和set等,势必在数据结构和算法层面上有诸多不适
我已经在用ssdb的hash结构,存储了很多数据了,但是我现在的用法正确吗? 我使用hash结构合理吗? 1. ssdb数据库说是类似redis,而且他们都有hash结构,但是他们的命名有点不同,ss ...
- 探索c#之跳跃表(SkipList)
阅读目录: 基本介绍 算法思想 演化步骤 实现细节 总结 基本介绍 SkipList是William Pugh在1990年提出的,它是一种可替代平衡树的数据结构. SkipList在实现上相对比较简单 ...
- [转载] 跳表SkipList
原文: http://www.cnblogs.com/xuqiang/archive/2011/05/22/2053516.html leveldb中memtable的思想本质上是一个skiplist ...
- 浅析SkipList跳跃表原理及代码实现
本文将总结一种数据结构:跳跃表.前半部分跳跃表性质和操作的介绍直接摘自<让算法的效率跳起来--浅谈“跳跃表”的相关操作及其应用>上海市华东师范大学第二附属中学 魏冉.之后将附上跳跃表的源代 ...
- 跳表SkipList
原文:http://www.cnblogs.com/xuqiang/archive/2011/05/22/2053516.html 跳表SkipList 1.聊一聊跳表作者的其人其事 2. 言归正 ...
- skiplist 跳表(2)-----细心学习
快速了解skiplist请看:skiplist 跳表(1) http://blog.sina.com.cn/s/blog_693f08470101n2lv.html 本周我要介绍的数据结构,是我非常非 ...
- skiplist 跳表(1)
最近学习中遇到一种新的数据结构,很实用,搬过来学习. 原文地址:skiplist 跳表 为什么选择跳表 目前经常使用的平衡数据结构有:B树,红黑树,AVL树,Splay Tree, Treep等. ...
随机推荐
- PHP使用feof()函数读文件的方法
这篇文章主要介绍了PHP使用feof()函数读文件的方法,以实例形式对比了正确与错误的用法,阐明了feof()函数的使用技巧,需要的朋友可以参考下 本文实例讲述了PHP使用feof()函数读文件的方法 ...
- C++ 如何有效地使用对话框
Q:如何在对话框中加入工具条 在 OnInitDialog 中加入下面代码: BOOL CYourDlg::OnInitDialog() { CDialog::OnInitDialog(); // C ...
- EXT学习之——EXT下拉框默认绑定第一个值
//默认第一个下拉框绑定值if (this.moduleCombo.store.getAt(0) != undefined) { this.moduleCombo.setValue(this.modu ...
- zedboard如何从PL端控制DDR读写(五)
有了前面的一堆铺垫.现在终于开始正式准备读写DDR了,开发环境:VIVADO2014.2 + SDK. 一.首先要想在PL端通过AXI去控制DDR,我们必须要有一个AXI master,由于是测试,就 ...
- HP XP7 GAD双活实现的理解
XP7双活的虚拟卷global active device (GAD)实际上对应两个存储的两个物理卷(有点儿像Mirror Disk镜像) 当主机A向阵列A发出写数据请求后,阵列A首先检查要被写入的数 ...
- VC MFC在CMFCToolBar工具栏中加入组合框
如何在CMFCToolBar工具栏中加入组合框等控件,且先看在线MSDN上怎么说的: 要增加一个组合框,需要完成以下步骤: 1.在工具栏资源中,增加一个对应ID资源号的按钮. 2.在主框架(mainf ...
- shell和bat 监控进程,自动关机
1.linux 下监控进程,进程结束后关机 新建文件 monit.sh $chmod +x monit.sh 加入代码 #!/bin/sh a=; ]; do |;then echo "sh ...
- collectionView使用细节
1.//创建组头组尾一个方法 - (UICollectionReusableView *)stCollectionView:(UICollectionView *)collectionView vie ...
- SQL Server Profiler使用方法
一.SQL Server Profiler使用方法 1.单击开始--程序--Microsoft SQL Server 2005--性能工具--SQL Server Profiler,如下图: 2. ...
- JDK的安装及部署配置(配图解)
JDK的安装及部署配置 双击安装文件,出现如下界面 点击[下一步]出现如下界面,更改安装路径(建议安装至D盘), 点击[下一步],出现如下界面,修改文件夹名. 点击[确定],耐心等待 直至出现如下界面 ...