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算法实现的更多相关文章

  1. 深夜学算法之SkipList:让链表飞

    1. 前言 上次写Python操作LevelDB时提到过,有机会要实现下SkipList.摘录下wiki介绍: 跳跃列表是一种随机化数据结构,基于并联的链表,其效率可比拟二叉查找树. 我们知道对于有序 ...

  2. 算法: skiplist 跳跃表代码实现和原理

    SkipList在leveldb以及lucence中都广为使用,是比较高效的数据结构.由于它的代码以及原理实现的简单性,更为人们所接受. 所有操作均从上向下逐层查找,越上层一次next操作跨度越大.其 ...

  3. ssdb底层实现——ssdb底层是leveldb,leveldb根本上是skiplist(例如为存储多个list items,必然有多个item key,而非暴力string cat),用它来做redis的list和set等,势必在数据结构和算法层面上有诸多不适

    我已经在用ssdb的hash结构,存储了很多数据了,但是我现在的用法正确吗? 我使用hash结构合理吗? 1. ssdb数据库说是类似redis,而且他们都有hash结构,但是他们的命名有点不同,ss ...

  4. 探索c#之跳跃表(SkipList)

    阅读目录: 基本介绍 算法思想 演化步骤 实现细节 总结 基本介绍 SkipList是William Pugh在1990年提出的,它是一种可替代平衡树的数据结构. SkipList在实现上相对比较简单 ...

  5. [转载] 跳表SkipList

    原文: http://www.cnblogs.com/xuqiang/archive/2011/05/22/2053516.html leveldb中memtable的思想本质上是一个skiplist ...

  6. 浅析SkipList跳跃表原理及代码实现

    本文将总结一种数据结构:跳跃表.前半部分跳跃表性质和操作的介绍直接摘自<让算法的效率跳起来--浅谈“跳跃表”的相关操作及其应用>上海市华东师范大学第二附属中学 魏冉.之后将附上跳跃表的源代 ...

  7. 跳表SkipList

    原文:http://www.cnblogs.com/xuqiang/archive/2011/05/22/2053516.html 跳表SkipList   1.聊一聊跳表作者的其人其事 2. 言归正 ...

  8. skiplist 跳表(2)-----细心学习

    快速了解skiplist请看:skiplist 跳表(1) http://blog.sina.com.cn/s/blog_693f08470101n2lv.html 本周我要介绍的数据结构,是我非常非 ...

  9. skiplist 跳表(1)

    最近学习中遇到一种新的数据结构,很实用,搬过来学习. 原文地址:skiplist 跳表   为什么选择跳表 目前经常使用的平衡数据结构有:B树,红黑树,AVL树,Splay Tree, Treep等. ...

随机推荐

  1. JAVA设计模式之解释器模式

    在阎宏博士的<JAVA与模式>一书中开头是这样描述解释器(Interpreter)模式的: 解释器模式是类的行为模式.给定一个语言之后,解释器模式可以定义出其文法的一种表示,并同时提供一个 ...

  2. UIAutomator 编译

    环境搭建 1.必备条件: 1.JDK    2.SDK(API高于15)    3.Eclipse(安装ADT插件)    4.ANT(用于编译生成jar) 2.简要步骤: 1.安装JDK并添加环境变 ...

  3. sql group by

    group by实例 实例一 数据表: 姓名 科目 分数 张三 语文 80 张三 数学 98 张三 英语 65 李四 语文 70 李四 数学 80 李四 英语 90 期望查询结果: 姓名 语文 数学 ...

  4. 通过AngularJS实现图片上传及缩略图展示

    从项目中截出的代码 HTML部分: <section> <img src="image/user-tuijian/tuijian_banner.png" /> ...

  5. JS 驗證英文字母

    //英文简介栏位焦点离开事件    function checkSummaryEN(SummaryEN) {        var val = $(SummaryEN).val();        v ...

  6. Brocade,Cisco SAN Switch命令对比

  7. C语言基础_2

    scanf函数可以从键盘上读取数据并记录到变量中.为了使用这个函数也需要在文件开头使用如下的预处理指令#include <stdio.h>scanf函数使用的时候所需要的初始数据和prin ...

  8. 调试CS5343总结报告

    一周前接到新任务,调试CS5343,百度一下,CS5343是一款音频采集的AD芯片,CS5343驱动代码是现成的,我的工作是提高芯片的采样速率,看了一边芯片的Datesheet,辛好东西不是很多. 概 ...

  9. Spring 4集成 Quartz2(转)

    本文将演示如何通过 Spring 使用 Quartz Scheduler 进行任务调度.Spring 为简化 Quartz 的操作提供了相关支持类.本文示例使用的相关工具如下: Spring 4.2. ...

  10. 计算机病毒实践汇总四:netcat使用方法

    在尝试学习分析的过程中,判断结论不一定准确,只是一些我自己的思考和探索.敬请批评指正! 1. netcat概述 (1)特性 "TCP/IP协议栈瑞士军刀",可以被用在支持端口扫描. ...