数据结构与算法学习--跳表

跳表

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;
}

猜你喜欢

转载自blog.csdn.net/jsh13417/article/details/83722066
今日推荐