zoukankan      html  css  js  c++  java
  • skiplist poj2892

    在微博上看到了skiplist,于是就想自己实现下下。

    关于skiplist的时间复杂度的证明还没看懂,有兴趣的可以去看看 Skip Lists:A ProbabilisticAlternative toBalanced Trees 这篇论文。

    ok,这里就只说实现了。

    其实论文里面的伪代码很清楚了,照着写就行了。

    skiplist就不多说了http://en.wikipedia.org/wiki/Skiplist

    还是使用我们喜闻乐见的c语言实现吧

    首先要的就是定义每个节点的数据类型啦。

    typedef struct snode
    {
      int key;
      int level;
      int value;
      struct snode* forward[maxlevel];
    }Node;

    每个节点有自己的level和forward指针,其实似乎level在每个节点定义木有啥用的哈- -,囧。。。

    然后定义skiplist的结构

    typedef struct slist
    {
      struct snode* head;
      int level;
    }skiplist;

    我看别人的代码里面有很多东西,但是我现在只是实现基本功能所以也就这两个就够了。

    然后是一些基本的makeNode , randomLevel等

    Node* makeNode(int newLevel , int key , int value)
    {
      Node* tmp = (Node *)malloc(sizeof(Node));
      tmp -> key = key;
      tmp -> value = value;
      tmp -> level = newLevel;
      return tmp;
    }
    
    int randomLevel()
    {
      int newLevel = 1;
      while((rand()&0xFFFF) < (0.4 * 0xFFFF))
         newLevel ++;
      return newLevel < maxlevel ? newLevel : maxlevel;
    }

    注意就是randomLevel,其实就是一个概率p,当rand < p的时候newLevel+1

    但是c语言似乎木有产生[0..1]随机数的函数,只有用rand()了

    用&0xFFFF把数字截断 , 然后p*0xFFFF来实现,不过感觉为啥p=0.5就死循环了,这个还没搞明白。

    void Init(skiplist * list)
    {
      list -> head = (Node*)malloc(sizeof(Node));
      for(int i = 0 ; i < maxlevel ; i++)
        list -> head -> forward[i] = NULL;
      list -> level = 0;
    }

    初始化skiplist

    好,关键的Insert , Delete来了

    void Insert(skiplist* list , int key , int value)
    {
      Node* update[maxlevel];
      Node* x = list -> head;
      for(int i = list -> level - 1 ; i >= 0 ; i--)
      {
        while(x -> forward[i] != NULL && x -> forward[i]->key < key)
          x = x -> forward[i];
        update[i] = x;
      }
      x = x -> forward[0];
      if(x != NULL && x -> key == key) x -> value = value;
      else{
        int newLevel = randomLevel();
        //   cout<< "level = " <<newLevel<<endl;
        if (newLevel > list -> level)
        {
          for(int i = list -> level ; i < newLevel ; i++)
        update[i] = list -> head;
          list -> level = newLevel;
        }
        x = makeNode(newLevel , key , value);
        for(int i = 0 ; i < newLevel ; i++)
        {
          x -> forward[i] = update[i] -> forward[i];
          update[i] -> forward[i] = x;
        }
      }
    }
    
    void Delete(skiplist* list , int key)
    {
      Node* update[maxlevel];
      Node* x = list -> head;
      for(int i = list -> level - 1 ; i >=0 ; i--)
      {
        while(x -> forward[i] != NULL && x -> forward[i] -> key < key)
          x = x -> forward[i];
        update[i] = x;
      }
      x = x -> forward[0];
      if(x != NULL && x -> key == key)
      {
        for(int i = 0 ; i < x -> level ; i++)
          if(update[i] -> forward[i] != x) break;
          else update[i] -> forward[i] = x -> forward[i];
        free(x);
        while(list -> level > 0 && list -> head -> forward[list -> level - 1] == NULL )
          list -> level --;
      }
    }

    一纬链表的插入,删除我们都懂,其实这个和那个一样的原理。

    对于插入就是先找到位置,就是key处于左右两边数字的中间的时候。

    然后新建节点,将前面的forward指向他,他的forward指向前面的forward。

    关键就是用一个update数组来记录x前面指向 它的节点(lasted),也就是x得前面节点。

    因为有多个forward,所以记录每个forward

    Delete同理。

    ==========================无敌分割线============================

    来做poj2892

    那就是将删除的点Insert

    如果rebuild那么久Delete

    如果Q,那么久找这个前面最大,和后面最小的,就是lessthan , greaterthan的操作

    因为在代码上改的,所以就没有把lessthan, greaterthan分别写成函数了

    int Search(skiplist* list , int key)
    {
      Node* x = list -> head;
      for(int i = list -> level - 1 ; i >=0 ; i--)
      {
        while(x -> forward[i] != NULL &&  x -> forward[i]-> key < key)
          x = x -> forward[i];
      }
      if(x -> forward[0] != NULL && x -> forward[0] -> key == key)
      {
        printf("0\n");
        return x -> value;
      }else{
        //right
        int right , left;
        if(x -> forward[0] == NULL)
          right = n ; else right = x -> forward[0] -> key - 1;
        if(x == list->head) left = 1 ; else  left = x -> key + 1;
        //   printf("left = %d , right = %d \n" , left , right);
        printf("%d\n",right - left + 1);
        return -1;
      }
    }

    ok...但是我初次乱写实现的效率很低很低。。。

    用g++交了还TLE,用C++交938MS。。差点超时。。。T——T有空慢慢改。。。

    by 1957
  • 相关阅读:
    JS常见面试题总结-真实被问到的!
    今天给大家分享一下js中常用的基础算法
    小程序创建自定义组件
    JavaScript里面9种数组遍历!
    第七章 restframework——url控制器
    第三章 Linux——目录结构
    第二章 Linux——基础命令使用
    第一章 Linux——系统介绍及环境搭建
    第六章 restframework——认证组件、权限组件、频率组件
    第五章 restframework——解析器
  • 原文地址:https://www.cnblogs.com/x1957/p/2716947.html
Copyright © 2011-2022 走看看