数据结构与算法—跳表(skiplist)
Posted 为了维护世界和平_
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构与算法—跳表(skiplist)相关的知识,希望对你有一定的参考价值。
目录
前言
二分查找用的数组
链表可不可以实现二分查找呢?
跳表
各方面性能比较优秀的动态数据结构,可以支持快速插入、删除、查找操作。写起来也不复杂,甚至可以代替红黑树。
跳表特点
对链表建立一级索引,每两个节点提取一个节点到上一级,叫做索引节点。
加一层索引之后,查找一个结点需要遍历的节点个数减少了,也就是查找效率提高了。
这种查找方式就是跳表
查询时间分析
1、时间复杂度 o(logn)
- 在单链表中查询某个数据的时间复杂度O(N)
- 跳表,n个节点,会有几层索引。
- 第k级索引的节点个数是k-1级索引节点个数的1/2;即 第k级索引节点的个数 n/2^k
- k = log2n-1,如果包含原始链表层,整个跳表的高度是log2 n
- 在跳表查找某个数据时,如果每一层需要遍历m个节点,那么跳表查询一个数据的时间复杂度O(m*logn)
- m是多少? 每一级索引最多只需要遍历3个节点, m = 3 常数
2、空间复杂度O(n)
索引节点的个数 n/2+n/4+n/8…+8+4+2=n-2 ,所以跳表的空间复杂度O(n)
意思是n个节点的单链表改成跳表,需要额外再用接近n个节点的内存空间。
在软件开发中原始链表中存储的有可能是很大的对象,而索引节点只需要存储关键值和几个指针,并不需要存储对象。所以当对象所以节点很大时,索引占用的空间可以忽略不计了。
动态插入和删除
插入、删除操作时间复杂度O(logn)
查找,需要遍历每个节点。查找时间复杂度O(logn)
删除,要拿到前驱节点,如果是双向链表,不需要考虑这个问题。
跳表动态更新
- 插入数据,如果跳表不更新,跳表会退化成单链表。
- 跳表通过随机函数维护 “平衡性”
- 往跳表中插入数据时,同时将数据插入到索引层中。(哪个索引层?)
通过随机函数,决定这个点插入到哪几级索引,如随机函数生成K,则节点添加到第一级到第K级索引中。
跳表与红黑树比较
1,按照区间查找数据,红黑树的效率没有跳表高。跳表O(logn)
2、跳表灵活,通过改变索引结构,有效平衡执行效率和内存消耗
3、红黑树一般有现成的可用,跳表需要自己实现
跳表实现
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<string.h>
typedef struct _node
int key;
int value;
int max_level;
struct _node *next[0];
node;
typedef struct _skiplist
int level;
int count;
node *head;
skiplist;
#define offsetof(TYPE,MEMBER) ((size_t) & ((TYPE *)0)->MEMBER)
#define container(ptr,type,member) (\\
const typeof( ((type *)0)->member) *__mptr = (ptr);\\
(type *) ( (char *)__mptr - offsetof(type,member));)
node * skip_list_create_node(int level,int key,int value)
node *tmp = NULL;
tmp = (node *)malloc(sizeof(node) + level*sizeof(node*));
assert(tmp !=NULL);
memset(tmp,0,sizeof(node) + level * sizeof(node*));
tmp->key = key;
tmp->value = value;
tmp->max_level = level;
return tmp;
skiplist *skip_list_create(int max_level)
int i=0;
skiplist *list = NULL;
list = (skiplist *)malloc(sizeof(skiplist));
assert(list != NULL);
list->level = 1;
list->count = 0;
list->head = skip_list_create_node(max_level,0,0);
if(list->head == NULL)
free(list);
return NULL;
return list;
void skip_list_destory(skiplist *list)
int i = 0;
node *tmp = NULL;
if((list == NULL) || list->head == NULL)
return ;
while(list->head->next[0] != NULL)
tmp = list->head->next[0];
list->head->next[0] = tmp->next[0];
free(tmp);
free(list->head);
free(list);
return;
int skip_list_level(skiplist *list)
int i = 0;
int level = 1;
for(i = 0;i<list->head->max_level;i++)
if(rand()%2 == 1)
level++;
return level;
int skip_list_insert(skiplist *list,int key,int value)
int i = 0;
int level = 0;
node **update = NULL;
node *tmp = NULL;
node *prev = NULL;
if(list == NULL)
return 1;
update = (node **)malloc(sizeof(node *)*list->head->max_level);
if(update == NULL)
return 2;
prev = list->head;
for(i = (list->level - 1);i>=0;i--)
while(((tmp = prev->next[i]) != NULL) && (tmp->key < key))
prev = tmp;
update[i] = prev;
if((tmp != NULL) && (tmp->key == key))
return 3;
//get ramdon level
level = skip_list_level(list);
tmp = skip_list_create_node(level,key,value);
if(tmp == NULL)
return 4;
//update max level,update
if(level > list->level)
for(i = list->level;i<level;i++)
update[i] = list->head;
list->level = level;
//update node pointer
for(i = 0;i<level;i++)
tmp->next[i] = update[i]->next[i];
update[i]->next[i] = tmp;
list->count++;
return 0;
int skip_list_search(skiplist *list,int key,int *value)
int i=0;
node *prev = NULL;
node *tmp = NULL;
if((list == NULL) || (list->count == 0) || (value == NULL))
return 1;
prev = list->head;
for(i = list->level - 1;i >= 0;i--)
//while(((tmp == prev->next[i])!=NULL) && (tmp->key<=key))
while(((tmp = prev->next[i]) != NULL) && (tmp->key <= key))
if(tmp->key == key)
*value = tmp->value;
return 0;
prev = tmp;
return -1;
void skip_list_dump(skiplist *list)
int i = 0;
node *ptmp = NULL;
printf("\\r\\n skiplist level[%d],count[%d]",list->level,list->count);
for(i = list->level -1 ;i>=0;i--)
ptmp = list->head->next[i];
printf("\\r\\n level[%d]:",i);
while(ptmp != NULL)
printf("%d-%d ",ptmp->key,ptmp->value);
ptmp = ptmp->next[i];
printf("\\r\\n-----------------------------------\\n");
return;
int skip_list_delete(skiplist *list,int key,int *value)
int i = 0;
node **update = NULL;
node *tmp = NULL;
node *prev = NULL;
if((list == NULL) && value == NULL || list->count ==0)
return 1;
update = (node **)malloc(sizeof(node *)*list->level);
if(update == NULL)
return 2;
prev = list->head;
for(i = (list->level - 1);i>=0;i++)
while((tmp = prev->next[i]) != NULL && (tmp->key < key))
prev=tmp;
update[i] = prev;
if((tmp != NULL) && (tmp->key == key))
*value = tmp->value;
for(i = 0;i<list->level;i++)
if(update[i]->next[i] == tmp)
update[i]->next[i] = tmp->next[i];
free(tmp);
tmp = NULL;
for(i = list->level -1 ;i>=0 ;i++)
if(list->head->next[i]==NULL)
list->level--;
else
break;
list->count--;
else
return 3;//not find
return 0;
int main()
int res = 0;
int key = 0;
int value = 0;
skiplist *list = NULL;
list = skip_list_create(8);
assert(list != NULL);
int i=0;
for(i = 0;i<30;i++)
key = value = i;
res = skip_list_insert(list,key,value);
if(res !=0)
printf("insert error res=%d\\n",res);
printf("insert down\\n");
skip_list_dump(list);
printf("############search#######\\n");
key = 10;
skip_list_search(list,key,&value);
printf("search value=%d\\n",value);
printf("############del############\\n");
skip_list_delete(list,key,&value);
printf("del value=%d\\n",value);
skip_list_dump(list);
# ./a.out
insert down
skiplist level[8],count[30]
level[7]:15-15
level[6]:15-15 16-16 23-23
level[5]:0-0 1-1 5-5 8-8 14-14 15-15 16-16 19-19 22-22 23-23 24-24
level[4]:0-0 1-1 3-3 4-4 5-5 6-6 7-7 8-8 13-13 14-14 15-15 16-16 17-17 18-18 19-19 22-22 23-23 24-24 27-27 29-29
level[3]:0-0 1-1 2-2 3-3 4-4 5-5 6-6 7-7 8-8 9-9 10-10 13-13 14-14 15-15 16-16 17-17 18-18 19-19 20-20 21-21 22-22 23-23 24-24 25-25 26-26 27-27 28-28 29-29
level[2]:0-0 1-1 2-2 3-3 4-4 5-5 6-6 7-7 8-8 9-9 10-10 11-11 12-12 13-13 14-14 15-15 16-16 17-17 18-18 19-19 20-20 21-21 22-22 23-23 24-24 25-25 26-26 27-27 28-28 29-29
level[1]:0-0 1-1 2-2 3-3 4-4 5-5 6-6 7-7 8-8 9-9 10-10 11-11 12-12 13-13 14-14 15-15 16-16 17-17 18-18 19-19 20-20 21-21 22-22 23-23 24-24 25-25 26-26 27-27 28-28 29-29
level[0]:0-0 1-1 2-2 3-3 4-4 5-5 6-6 7-7 8-8 9-9 10-10 11-11 12-12 13-13 14-14 15-15 16-16 17-17 18-18 19-19 20-20 21-21 22-22 23-23 24-24 25-25 26-26 27-27 28-28 29-29
-----------------------------------
############search############
search value=10
############del############
del value=10
skiplist level[8],count[29]
level[7]:15-15
level[6]:15-15 16-16 23-23
level[5]:0-0 1-1 5-5 8-8 14-14 15-15 16-16 19-19 22-22 23-23 24-24
level[4]:0-0 1-1 3-3 4-4 5-5 6-6 7-7 8-8 13-13 14-14 15-15 16-16 17-17 18-18 19-19 22-22 23-23 24-24 27-27 29-29
level[3]:0-0 1-1 2-2 3-3 4-4 5-5 6-6 7-7 8-8 9-9 13-13 14-14 15-15 16-16 17-17 18-18 19-19 20-20 21-21 22-22 23-23 24-24 25-25 26-26 27-27 28-28 29-29
level[2]:0-0 1-1 2-2 3-3 4-4 5-5 6-6 7-7 8-8 9-9 11-11 12-12 13-13 14-14 15-15 16-16 17-17 18-18 19-19 20-20 21-21 22-22 23-23 24-24 25-25 26-26 27-27 28-28 29-29
level[1]:0-0 1-1 2-2 3-3 4-4 5-5 6-6 7-7 8-8 9-9 11-11 12-12 13-13 14-14 15-15 16-16 17-17 18-18 19-19 20-20 21-21 22-22 23-23 24-24 25-25 26-26 27-27 28-28 29-29
level[0]:0-0 1-1 2-2 3-3 4-4 5-5 6-6 7-7 8-8 9-9 11-11 12-12 13-13 14-14 15-15 16-16 17-17 18-18 19-19 20-20 21-21 22-22 23-23 24-24 25-25 26-26 27-27 28-28 29-29
-----------------------------------
以上是关于数据结构与算法—跳表(skiplist)的主要内容,如果未能解决你的问题,请参考以下文章