skip list

 

概述

Skip list是平衡树的一种替代的数据结构,但是和红黑树不相同的是,跳表对于树的平衡的实现是基于一种随机化的算法的,这样也就是说跳表的插入和删除的工作是比较简单的。并且是Redis、LevelDB、nessDB、SkipDB等的底层结构,学习skip list为后面学习levelDB打下基础。

核心思想

如果是一个简单的链表,如图1,那么我们知道在链表中查找一个元素I的话,需要将整个链表遍历一次。

wps_clip_image-3871

图 1

如果是说链表是排序的,并且节点中还存储了指向前面第二个节点的指针的话,如图2,那么在查找一个节点时,仅仅需要遍历N/2个节点即可。

wps_clip_image-20091

图 2

这基本上就是跳表的核心思想,其实也是一种通过“空间来换取时间”的一个算法,通过在每个节点中增加了向前的指针,从而提升查找的效率。

跳表数据存储模型

我们定义:

如果一个基点存在k个向前的指针的话,那么陈该节点是k层的节点。

一个跳表的层MaxLevel定义为跳表中所有节点中最大的层数。

下面给出一个完整的跳表的图示:

wps_clip_image-6767

那么我们该如何将该数据结构使用二进制存储呢?通过上面的跳表的很容易设计这样的数据结构:

定义每个节点类型:

typedef struct NodeStructure *Node;

typedef struct NodeStructure

{

keyType key; // key值

valueType value; // value值

// 向前指针数组,根据该节点层数的不同指向不同大小的数组

NodeStructure *forward[1];

}NodeStructure;wps_clip_image-6442

上面的每个结构体对应着图中的每个节点,如果一个节点是一层的节点的话(如7,12等节点),那么对应的forward将指向一个只含一个元素的数组,以此类推。

定义跳表数据类型:

// 定义跳表数据类型

typedef struct SkipList{

int level;  /* Maximum level of the list

          (1 more than the number of levels in the list) */

Node header; /* pointer to header */

} * SkipList;跳表数据类型中包含了维护跳表的必要信息,level表明跳表的层数,header如下所示:

wps_clip_image-13092

定义辅助变量:

#define MAX_LEVEL 10

定义辅助方法:

创建节点

Node CreateNode(int level,int key,int value) 

     Node node=(NodeStructure *)malloc(sizeof(NodeStructure)+level*sizeof(NodeStructure*));   

     node->key=key;   

    node->value=value;   

return node;   

好的基本的数据结构定义已经完成,接下来来分析对于跳表的一个操作。

跳表代码实现
1 初始化

初始化的过程很简单,仅仅是生成下图中红线区域内的部分,也就是跳表的基础结构:

wps_clip_image-10466

SkipList CreateSkiplist() 

     SkipList skiplist=(SkipList *)malloc(sizeof(struct SkipList));    

     skiplist->level=0;      

     skiplist->header=CreateNode(MAX_LEVEL-1,0,0);  

for(int i=0;i<MAX_LEVEL;i++)      

{   

        skiplist->header->forward[i]=NULL;   

    } 

    return skiplist; 

}

2 查找

//搜索指定key的value 

int Search(SkipList skiplist,int key) 

     Node pre,now=NULL; 

     pre=skiplist->header; 

     //从最高层开始搜 

     int k=skiplist->level; 

     for(int i=k-1; i >= 0; i--)

         while((now=pre->forward[i])&&(now->key<=key)) 

         { 

             if(now->key == key) 

             { 

                 return now->value; 

             pre=now; 

         } 

     } 

     return NULL; 

3 插入操作

由于跳表数据结构整体上是有序的,所以在插入时,需要首先查找到合适的位置,然后就是修改指针(和链表中操作类似),然后更新跳表的level变量。

wps_clip_image-10772

//随机产生层数 

int randomLevel()   

    int k=1; 

while (rand()%2)   

k++;   

k=(k<MAX_LEVEL)?k:MAX_LEVEL; 

return k;   

//插入节点 

bool Insert(SkipList *skiplist,int key,int value) 

     Node update[MAX_LEVEL]; 

     Node p, q = NULL; 

     p=skiplist->header; 

    int k=skiplist->level; 

//从最高层往下查找需要插入的位置 

     //填充update 

     for(int i=k-1; i >= 0; i--)

//q!=NULL

         while((q=p->forward[i])&&(q->key<key)) 

         { 

             p=q; 

         } 

        update[i]=p; 

     } 

// 这里已经查找到了合适的位置,并且update数组已经

// 填充好了元素

     //不能插入相同的key 

     if(q&&q->key==key) 

    { 

         return false; 

     } 

     //产生一个随机层数K 

    //新建一个待插入节点q 

//一层一层插入 

     k=randomLevel();

// 如果新生成的层数比跳表的层数大的话

// 增加整个跳表的层数

if(k>(skiplist->level)) 

     { 

         for(int i=skiplist->level; i < k; i++)

// 在update数组中将新添加的层指向skiplist->header

            update[i] = skiplist->header; 

         } 

         skiplist->level=k; 

     } 

    q=CreateNode(k,key,value); 

//逐层更新节点的指针,和普通列表插入一样 

     for(int i=0;i<k;i++) 

    { 

q->forward[i]=update[i]->forward[i]; 

        update[i]->forward[i]=q; 

     } 

     return true; 

4 删除某个节点

和插入是相同的,首先查找需要删除的节点,如果找到了该节点的话,那么只需要更新指针域,如果跳表的level需要更新的话,进行更新。

wps_clip_image-14063

//删除指定的key 

bool Delete(SkipList skiplist,int key) 

    Node update[MAX_LEVEL]; 

Node p,q=NULL; 

    p=skiplist->header; 

    //从最高层开始搜 

     int k=skiplist->level; 

     for(int i=k-1; i >= 0; i--)

        while((q=p->forward[i])&&(q->key<key)) 

         { 

             p=q; 

         } 

         update[i]=p; 

     } 

     if(q&&q->key==key) 

     { 

         //逐层删除,和普通列表删除一样 

         for(int i=0; i<skiplist->level; i++)

{   

             if(update[i]->forward[i]==q)

{   

                update[i]->forward[i]=q->forward[i];   

            } 

        }  

         free(q); 

         //如果删除的是最大层的节点,那么需要重新维护跳表的 

        for(int i=skiplist->level - 1; i >= 0; i--)

{   

            if(skiplist->header->forward[i]==NULL)

{   

                skiplist->level--;   

             }   

         }   

         return true; 

     } 

    else 

         return false; 

}

5 参考文献

SkipList论文

ftp://ftp.cs.umd.edu/pub/skipLists/skiplists.pdf

#define MAX_LEVEL 10
typedef struct NodeStructure *Node;

typedef struct NodeStructure
{
	keyType key; // key值
	valueType value; // value值
	// 向前指针数组,根据该节点层数的不同指向不同大小的数组
	NodeStructure *forward[1]; 
}NodeStructure;

typedef struct SkipList{
	int level;  /* Maximum level of the list 
  	          (1 more than the number of levels in the list) */
	Node header; /* pointer to header */
} * SkipList;

Node CreateNode(int level,int key,int value)  
 {  
     Node node=(NodeStructure *)malloc(sizeof(NodeStructure)+level*sizeof(NodeStructure*));    
     node->key=key;    
    node->value=value;    
	return node;    
}  

SkipList CreateSkiplist()  
{  
     SkipList skiplist=(SkipList *)malloc(sizeof(struct SkipList));     
     skiplist->level=0;       
     skiplist->header=CreateNode(MAX_LEVEL-1,0,0);   
	 
	for(int i=0;i<MAX_LEVEL;i++)       
	{    
        skiplist->header->forward[i]=NULL;    
    }  
    return skiplist;  
 }  

 
 //搜索指定key的value  
int Search(SkipList skiplist,int key)  
{  
     Node pre,now=NULL;  
     pre=skiplist->header;  
     //从最高层开始搜  
     int k=skiplist->level;  
     for(int i=k-1; i >= 0; i--)
	 {  
         while((now=pre->forward[i])&&(now->key<=key))  
         {  
             if(now->key == key)  
             {  
                 return now->value;  
			 }  
             pre=now;  
         }  
     }  
     return NULL;  
 }  

 //随机产生层数  
int randomLevel()    
{  
    int k=1;  
	while (rand()%2)    
	k++;    
	k=(k<MAX_LEVEL)?k:MAX_LEVEL;  
	return k;    
 }  

 //插入节点  
 bool Insert(SkipList skiplist,int key,int value)  
{  
     Node update[MAX_LEVEL];  
     Node p, q = NULL;  
     p=skiplist->header;  
    int k=skiplist->level;  
	//从最高层往下查找需要插入的位置  
     //填充update  
     for(int i=k-1; i >= 0; i--)
	 {  
		 //q!=NULL
         while((q=p->forward[i])&&(q->key<key))  
         {  
             p=q;  
         }  
        update[i]=p;  
     }  
	 // 这里已经查找到了合适的位置,并且update数组已经
	 // 填充好了元素
     //不能插入相同的key  
     if(q&&q->key==key)  
    {  
         return false;  
     }  
     
     //产生一个随机层数K  
    //新建一个待插入节点q  
	//一层一层插入  
     k=randomLevel();
	// 如果新生成的层数比跳表的层数大的话
	// 增加整个跳表的层数	  
	if(k>(skiplist->level))  
     {  
         for(int i=skiplist->level; i < k; i++)
		 {  
			// 在update数组中将新添加的层指向skiplist->header
            update[i] = skiplist->header;  
         }  
         skiplist->level=k;  
     }  
     
    q=CreateNode(k,key,value);  
	//逐层更新节点的指针,和普通列表插入一样  
     for(int i=0;i<k;i++)  
    {  
		q->forward[i]=update[i]->forward[i];  
        update[i]->forward[i]=q;  
     }  
     return true;  
 }  
 
 //删除指定的key  
bool Delete(SkipList skiplist,int key)  
{  
    Node update[MAX_LEVEL];  
	Node p,q=NULL;  
    p=skiplist->header;  
    //从最高层开始搜  
     int k=skiplist->level;  
     for(int i=k-1; i >= 0; i--)
	 {  
        while((q=p->forward[i])&&(q->key<key))  
         {  
             p=q;  
         }  
         update[i]=p;  
     }  
     if(q&&q->key==key)  
     {  
         //逐层删除,和普通列表删除一样  
         for(int i=0; i<skiplist->level; i++)
		 {    
             if(update[i]->forward[i]==q)
			 {    
                update[i]->forward[i]=q->forward[i];    
            }  
        }   
         free(q);  
         //如果删除的是最大层的节点,那么需要重新维护跳表的  
        for(int i=skiplist->level - 1; i >= 0; i--)
		{    
            if(skiplist->header->forward[i]==NULL)
			{    
                skiplist->level--;    
             }    
         }    
         return true;  
     }  
    else  
         return false;  
 }  
 
 
 void Print(SkipList skiplist)  
 {  
    //从最高层开始打印  
     nodeStructure *p,*q=NULL;  
     
     //从最高层开始搜  
     int k=skiplist->level;  
	for(int i=k-1; i >= 0; i--)  
	{  
         p=skiplist->header;  
        while(q=p->forward[i])  
		{  
			printf("%d -> ",p->value);  
			p=q;  
         }  
         printf("\n");  
     }  
     printf("\n");  
 }
 
 int main()  
 {  
     SkipList skiplist=CreateSkiplist();  
     for(int i=1;i<=19;i++)  
     {  
         Insert(skiplist,i,i*2);  
     }  
     Print(skiplist);  
     //搜索  
     int i=Search(skiplist,4);  
     printf("i=%d\n",i);  
     //删除  
     bool b=Delete(skiplist,4);  
     if(b)  
         printf("删除成功\n");  
     Print(skiplist);  
    system("pause");  
     return 0;  
 }  

  

posted @ 2013-10-26 16:29  TheBug  阅读(1290)  评论(0编辑  收藏  举报