skiplist poj2892

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

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

ok,这里就只说实现了。

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

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

skiplist poj2892

还是使用我们喜闻乐见的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有空慢慢改。。。

你可能感兴趣的:(plist)