zoukankan      html  css  js  c++  java
  • 跳表

    参考了这篇博客,再加上自己的理解,总结了跳表的一些知识。

    1. 概念

      基于并联的链表,跳表是一种随机化的数据结构,在插入、删除、查找的复杂性都是O(logN)。它是链表的一种,只不过加入了跳跃功能,正是因为这个特性,使得它的查找复杂度是O(logN)。

      跳表是平衡树的一种替代的数据结构,但是和红黑树不相同的是,跳表对于树的平衡的实现是基于一种随机化的算法的,这样也就是说跳表的插入和删除的工作是比较简单的。

    2. 实现原理

    跳表采用的是“空间换取时间”的原理

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

    image_1bdednsle7jc1b391krr1tll321g.png-11.3kB

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

    image_1bdedok8m134s6qi15io1tu11aln1t.png-15kB

    • 基本实现
      • 一个跳表应该有几个层(level)组成
      • 第一层包含所有的元素
      • 每一层都是一个有序的链表
      • 如果x出现在第i层,则所有比i小的层都包含x
      • 每个结点包含key及其对应的value和一个指向同一层链表的下个结点的指针数组

    image_1bdedkc85savduakvtl0ejsc13.png-18.9kB

    3. 代码实现

    • 先定义每个结点的指针:
        typedef struct nodeStructure *node;
        typedef struct nodeStructure
        
        {
            keyType key;	// key值
            valueType value;	// value值
            // 向前指针数组,根据该节点层数的
            // 不同指向不同大小的数组
            node forward[1]; //柔性数组	
        };
    
    • 定义跳表类型
        typedef struct listStructure{
            int level; 	  /* Maximum level of the list */
            struct nodeStructure * header; /* pointer to header */
        } * list; 
    

    image_1bdegfohmtqe15vnfb1lfbfet2a.png-22.3kB

    • 定义辅助变量和函数:
        node NIL = nullptr;
        #define MaxNumberOfLevels 16
        #define MaxLevel (MaxNumberOfLevels-1) 
        #define newNodeOfLevel(l) (node)malloc(sizeof(struct nodeStructure)+(l)*sizeof(node *))
        
        //插入元素的时候元素所占有的层数完全是随机算法
        int randomLevel()
        {
    	    int level=1;
            while (rand()%2)
                level++;
            return level;
        }
    
    
    • 初始化成红线部分

    image_1bdegp8bs389auu147q1crttcn2n.png-21.5kB

        list newList()
        {
            list l;
            int i;
            // 申请list类型大小的内存
            l = new listStructure;
            // 设置跳表的层level,初始的层为0层(数组从0开始)
            l->level = 0;
          
            // 生成header部分
            l->header = new listStrutcure;
            // 将header的forward数组清空
            for(i=0;i<MaxNumberOfLevels;i++) {
                l->header->forward[i] = new nodeStructure;
                l->header->forward[i] = NIL;
            }
            return l;
        };  
    
    • 插入操作

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

    image_1bdelauac1knl3pu8s9hpi9q34.png-72.8kB

        boolean insert(l,key,value) 
    	register list l;
    	register keyType key;
    	register valueType value;
        {
          register int k;
          // 使用了update数组
          node update[MaxNumberOfLevels];
          register node p,q;
          p = l->header;
          k = l->level;
          /*******************1步*********************/
          do {
        		// 查找插入位置
        		while (q = p->forward[k], q->key < key)
        			p = q;
        		
        		// 设置update数组
        		update[k] = p;
        	} while(--k>=0);	// 对于每一层进行遍历
        	
        	// 这里已经查找到了合适的位置,并且update数组已经
        	// 填充好了元素
           if (q->key == key)
           {
             q->value = value;
             return(false);
           };
        	
           // 随机生成一个层数
           k = randomLevel();  
          if (k>l->level) 
          {
          	// 如果新生成的层数比跳表的层数大的话
            // 增加整个跳表的层数
        	k = ++l->level;
        	// 在update数组中将新添加的层指向l->header
        	update[k] = l->header;
          };
        		
          /*******************2步*********************/
          // 生成层数个节点数目
          q = newNodeOfLevel(k);
          q->key = key;
          q->value = value;
              
          // 更新两个指针域
          do 
          {
        		p = update[k];
        		q->forward[k] = p->forward[k];
        		p->forward[k] = q;
        	} while(--k>=0);
        	
        	// 如果程序运行到这里,程序已经插入了该节点
          return(true);
        } 
    
    • 删除操作

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

    image_1bdem9sj9kqr1ngl123218pl1h2a3h.png-57.6kB

        boolean delete(l,key) 
        register list l;
        register keyType key;
        {
            register int k,m;
            // 生成一个辅助数组update
            node update[MaxNumberOfLevels];
            register node p,q;
            p = l->header;
            k = m = l->level;
            // 这里和插入部分类似,最终update中包含的是:
            // 指向该节点对应层的前驱节点
            do 
            {
        		while (q = p->forward[k], q->key < key) 
        			p = q;
        		update[k] = p;
        	} while(--k>=0);
        	// 如果找到了该节点,才进行删除的动作
            if (q->key == key) 
            {
          	    // 指针运算
        		for(k=0; k<=m && (p=update[k])->forward[k] == q; k++) 
        		    // 这里可能修改l->header->forward数组的值的 
        		    p->forward[k] = q->forward[k];
        		// 释放实际内存
        		free(q);
        		
        		// 如果删除的是最大层的节点,那么需要重新维护跳表的
        		// 层数level
           	while( l->header->forward[m] == NIL && m > 0 )
        	    m--;
        		l->level = m;
        		return(true);
        	}
            else
          	// 没有找到该节点,不进行删除动作 
            return(false);
        } 
    
    • 查找操作

      查找操作前面都提到过,特别简单

        boolean search(l,key,valuePointer)
            register list l;
            register keyType key;
            valueType * valuePointer;
        {
            register int k;
            register node p,q;
            p = l->header;
            k = l->level;
            do 
            {
      	        while (q = p->forward[k], q->key < key) 
      		        p = q;
            } while (--k>=0);
            // 这里查找到的值是大于或者是等于需要查找的key值的
            if (q->key != key) 
                return(false);
            *valuePointer = q->value;
            return(true);
        };
    
    
  • 相关阅读:
    【codevs1922】骑士共存问题——网络流
    【bzoj1855||hdu3401】股票交易——单调队列优化dp
    【bzoj2002】弹飞绵羊——分块
    【bzoj3790】神奇项链——manacher+贪心
    【hdu2149】Public Sale
    【hdu1846】Brave Game
    【hdu3294】Girls' research——manacher
    【hdu3068】最长回文——manacher算法
    [BZOJ] 1634: [Usaco2007 Jan]Protecting the Flowers 护花
    [BZOJ] 1651: [Usaco2006 Feb]Stall Reservations 专用牛棚
  • 原文地址:https://www.cnblogs.com/vachester/p/6696806.html
Copyright © 2011-2022 走看看