跳表
Skip List是一种随机化的数据结构,基于并联的链表,其效率可比拟于二叉查找树(对于大多数操作需要O(log n)平均时间)。基本上,跳跃列表是对有序的链表增加上附加的前进链接,增加是以随机化的方式进行的,所以在列表中的查找可以快速的跳过部分列表(因此得名)。所有操作都以对数随机化的时间进行。Skip List可以很好解决有序链表查找特定值的困难。
跳表的定义及如何构造跳表
构造一个有序的单链表,我们查找某个元素,平均时间复杂度0(n)。
Skip List构造步骤:
为一个值有序的链表建立多级索引,比如每2个节点提取一个节点到上一级,我们把抽出来的那一级叫做索引或索引层。如下图所示,其中down表示down指针,指向下一级节点。以此类推,对于节点数为n的链表,大约可以建立log2n-1级索引。像这种为链表建立多级索引的数据结构就称为跳表。
二、跳表的时间复杂度?
1.计算跳表的高度
如果链表有n个节点,每2个节点抽取抽出一个节点作为上一级索引的节点,那第1级索引的节点个数大约是n/2,第2级索引的节点个数大约是n/4,依次类推,第k级索引的节点个数就是n/(2k)。假设索引有h级别,最高级的索引有2个节点,则有n/(2h)=2,得出h=log2n-1,包含原始链表这一层,整个跳表的高度就是log2n。
2.计算跳表的时间复杂度
假设我们在跳表中查询某个数据的时候,如果每一层都遍历m个节点,那在跳表中查询一个数据的时间复杂度就是O(m*logn)。那这个m是多少呢?如下图所示,假设我们要查找的数据是x,在第k级索引中,我们遍历到y节点之后,发现x大于y,小于后面的节点z,所以我们通过y的down指针,从第k级下降到第k-1级索引。在第k-1级索引中,y和z之间只有3个节点(包含y和z),所以,我们在k-1级索引中最多只需要遍历3个节点,以此类推,每一级索引都最多只需要遍历3个节点。所以m=3。因此在跳表中查询某个数据的时间复杂度就是O(logn)。
三、跳表的空间复杂度及如何优化?
1.计算索引的节点总数
如果链表有n个节点,每2个节点抽取抽出一个节点作为上一级索引的节点,那每一级索引的节点数分别为:n/2,n/4,n/8,…,8,4,2,等比数列求和n-1,所以跳表的空间复杂度为O(n)。
2.如何优化时间复杂度
如果链表有n个节点,每3或5个节点抽取抽出一个节点作为上一级索引的节点,那每一级索引的节点数分别为(以3为例):n/3,n/9,n/27,…,27,9,3,1,等比数列求和n/2,所以跳表的空间复杂度为O(n),和每2个节点抽取一次相比,时间复杂度要低不少呢。
四、高效的动态插入和删除?
跳表本质上就是链表,所以仅插作,插入和删除操时间复杂度就为O(1),但在实际情况中,要插入或删除某个节点,需要先查找到指定位置,而这个查找操作比较费时,但在跳表中这个查找操作的时间复杂度是O(logn),所以,跳表的插入和删除操作的是时间复杂度也是O(logn)。
五、跳表索引动态更新?
当往跳表中插入数据的时候,可以选择同时将这个数据插入到部分索引层中,那么如何选择这个索引层呢?可以通过随机函数来决定将这个节点插入到哪几级索引中,比如随机函数生成了值K,那就可以把这个节点添加到第1级到第K级索引中。
下面是跳表的C代码的实现及简单的调试。
/*************************************************************************
> File Name: skiplist.h
> Author: jinshaohui
> Mail: [email protected]
> Time: 18-10-31
> Desc:
************************************************************************/
#ifndef __SKIP_LIST_H__
#define __SKIP_LIST_H__
typedef struct _node
{
int key; /*key是唯一的*/
int value; /*存储的内容*/
int max_level; /*当前节点最大层数*/
struct _node *next[0];/*level层链表结构*/
}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));})
#endif
/*************************************************************************
> File Name: skiplist.c
> Author: jinshaohui
> Mail: [email protected]
> Time: 18-10-31
> Desc:
************************************************************************/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>
#include"./skiplist.h"
/*创建node节点*/
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;
}
/*创建跳表的表头,max_level层数*/
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;
}
/*skiplist 销毁*/
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 = 1; 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空间用于保存每层的指针*/
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--)
{
/*初始化每level层的头指针*/
while(((tmp = prev->next[i]) != NULL) && (tmp->key < key))
{
prev = tmp;
}
update[i] = prev;
}
/*当前key已经存在,返回错误*/
if ((tmp!= NULL) && (tmp->key == key))
{
return 3;
}
/*获取插入元素的随机层数,并更新跳表的最大层数*/
level = skip_list_level(list);
/*创建当前数据节点*/
tmp = skip_list_create_node(level,key,value);
if (tmp == NULL)
{
return 4;
}
/*更新最大层数*/
if (level > list->level)
{
for (i = list->level;i < level; i ++)
{
update[i] = list->head;
}
list->level = level;
}
/*逐层更新节点的指针*/
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_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空间用于保存每层的指针*/
update = (node **)malloc(sizeof(node *)*list->level);
if (update == NULL)
{
return 2;
}
/*逐层查询节点的*/
prev = list->head;
for (i = (list->level -1); i >= 0; i--)
{
/*初始化每level层的头指针*/
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;
/*更新level的层数*/
for (i = list->level - 1; i >= 0; i++)
{
if (list->head->next[i] == NULL )
{
list->level--;
}
else
{
break;
}
}
list->count--;
}
else
{
return 3;/*未找到节点*/
}
return 0 ;
}
/*查询当前key是否在跳表中,如果存在返回查询的value数值,不存在返回-1*/
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))
{
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----------------------------------------------");
printf("\r\n skip list 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----------------------------------------------");
return;
}
int main()
{
int res = 0;
int key = 0;
int value = 0;
skiplist *list = NULL;
list = skip_list_create(5);
assert(list != NULL);
while(1)
{
printf("\r\n 请输入key 和 value,当key = 1000时,退出输入:");
scanf("%d%d",&key,&value);
if (key == 1000)
{
break;
}
res = skip_list_insert(list,key,value);
if (res != 0)
{
printf("\r\n skip list insert %d,failed,res=%d.",key,res);
}
}
skip_list_dump(list);
while(1)
{
printf("\r\n 通过key 查询value的数值,当key = 1000时,退出查询");
scanf("%d",&key);
if(key == 1000)
{
break;
}
res = skip_list_search(list,key,&value);
if (res != 0)
{
printf("\r\n skip list search %d,failed,res=%d.",key,res);
}
else
{
printf("\r\n skip list search %d,sucessful,value=%d.",key,value);
}
}
skip_list_dump(list);
while(1)
{
printf("\r\n 通过key 删除节点,当key = 1000时,退出删除");
scanf("%d",&key);
if(key == 1000)
{
break;
}
res = skip_list_delete(list,key,&value);
if (res != 0)
{
printf("\r\n skip list search %d,failed,res=%d.",key,res);
}
else
{
printf("\r\n skip list search %d,sucessful,value=%d.",key,value);
}
}
skip_list_dump(list);
skip_list_destory(list);
return 0;
}