跳跃表的定义及实现

跳跃表:
Skip List是一种随机化的数据结构,基于并联的链表,其效率可比拟于二叉查找树(对于大多数操作需要O(log n)平均时间)。
基本上,跳跃列表是对有序的链表增加上附加的前进链接,增加是以随机化的方式进行的,所以在列表中的查找可以快速的跳过部分列表(因此得名)。
所有操作都以对数随机化的时间进行。Skip List可以很好解决有序链表查找特定值的困难。

一个跳表,应该具有以下特征:
1.一个跳表应该有几个层(level)组成;
2. 跳表的第一层包含所有的元素;
3. 每一层都是一个有序的链表;
4.如果元素x出现在第i层,则所有比i小的层都包含x;
5.第i层的元素通过一个down指针指向下一层拥有相同值的元素;
6.在每一层中,都有INT_MIN作为起始结点,INT_MAX作为结束结点。 //这里其实也可以用初始化的方式直接把排序过的链表的最小值作为起始结点,最大值作为结束结点,并且最大层为maxlevel

7.root指针指向最高层的第一个元素。

基于以上,我对这个跳跃表的理解,认为这种数据结构 主要用于存储拥有大量结点,并且需要增删减查功能的链表。建立的跳跃表结点结构体:

typedef struct Slnode
{
int data;           //数据
unsigned level;     //层
struct Slnode *next;
struct Slnode *down;
Slnode(int d,unsigned lev):data(d),level(lev),next(NULL),down(NULL){}
Slnode(int d):data(d),level(1),next(NULL),down(NULL){}
}Slnode;

每个结点都需要保存当前的数据和层数,以及横向(next)以及纵向(down)指针信息。

边写才边发现,其实我用于存储的 int data应该要作为数据索引更改为 int key,并且不允许插入相同的key,然后在结点中再增加一项typedef data作为需要存储的数据才是一个正确的跳跃表(感觉有点象哈希了hahah)

不过由于时间原因,我就先放这了,大略思想应该是对的。

/*
跳跃表方法:
    Skitlist(unsigned max = 3) //构造函数,可以自定义最大层次,默认为3
    addnode(int data) //插入结点,数据为data
    size()  //返回第一层数据个数
    findnode(int data) //查找结点,根据特定的数据查找到该结点并返回(就是这里觉得不对劲的,开始我写得函数原型是用data查data,hahah简直有病,所以觉得data应该更改为key,并且结点中增加一项 typedef data;)
    deledata(int data) //根据data删除该结点
    PrBottom() //显示第一层元素排列情况
    Prtotol()  //显示所有层元素排列情况
*/

#include<iostream>
#include<cstdlib>   //需要利用rand()
#include<ctime>     //利用系统时间获取随机数种子
typedef struct Slnode
{
int data;         //数据
unsigned level;   //层
struct Slnode *next;
struct Slnode *down;
Slnode(int d,unsigned lev):data(d),level(lev),next(NULL),down(NULL){}
Slnode(int d):data(d),level(1),next(NULL),down(NULL){}
}Slnode;


class Skitlist
{
private:
    Slnode *root;  //root指针指向最高层的第一个元素。
    unsigned Maxlevel;
    unsigned nodecount;

public:
Skitlist(unsigned max = 3):Maxlevel(max),nodecount(0)  //默认三层   构造函数给出了跳跃表开始的头和尾
{
      root = new Slnode(INT_MIN,Maxlevel);         //初始跳表第一个顶层结点
      root->next = new Slnode(INT_MAX,Maxlevel);   //初始跳表第二个顶层结点

      Slnode *temph = root;
      Slnode *templ = root->next;

      for(int i = 1;i<Maxlevel;i++)
      {
        Slnode *temp = new Slnode(root->next->data,root->next->level-i); //最后一个结点不用指向后面的结点了,所以先解决最后的结点
        templ->down = temp;
        /*root->next向下一层复制结点*/
        temp = new Slnode(root->data,root->level-i);
        temph->down = temp;
         /*root向下一层复制结点*/
        templ = templ->down;
        temph = temph->down;
        temph->next = templ;  //同层也用next连接
      }
}

unsigned randomLevel()  //利用随机数产生一个不大于Maxlevel的数
{
 // srand((unsigned)time(NULL));
  unsigned k=1;
  while (rand()%2)
    k++;
  k=(k<Maxlevel)?k:Maxlevel;
    return k;
}


void addnode(int data)  //插入结点,自动分配层次和位置
{
      Slnode *node = new Slnode(data,randomLevel());//创建结点,并且确定层次
      Slnode *dnode = node;

      Slnode *temp = root;

      std::cout<<"新添加结点数据:"<<node->data<<"  level:"<<node->level<<std::endl;

      for(;temp&&temp->next;temp=temp->down)        //右下角一直走,但不能走到最后一个结点之后
      {
        while(temp->next->data < node->data)      //把新结点按大小顺序插入链表中(插到最底层的temp->next中)
        {
         temp = temp->next;
        }                                       //没到底层前需要下移了,可以把data结点插进来
       if(temp->level == node->level)
       {
      // Slnode *nodez = new Slnode(node->data,temp->level);
       node->next = temp->next;
       temp->next = node;
       }
       else if(temp->level < node->level)
       {
         Slnode *nodez = new Slnode(node->data,temp->level);
          nodez->next = temp->next;
          temp->next = nodez;
          dnode->down = nodez;
          dnode = nodez;
       }
      }
     nodecount++;
}

unsigned size(){return nodecount;}

Slnode* findnode(int data)  //返回元素的指针
{
  Slnode *temp = root;
  int findcount = 0;
  while(temp)
  {
      while(temp->next->data<=data && temp->next->data!=INT_MAX)
      {
         temp = temp->next;
          findcount++;
          std::cout<<"前进一步"<<std::endl;
          if(data==temp->data)
            {
              std::cout<<"总共走了"<<findcount<<"步"<<std::endl;
              return temp;
            }
      }

   temp = temp->down;
   std::cout<<"下走一步"<<"temp.level:"<<temp->data<<std::endl;
   findcount++;
  }

  return NULL;
}


void deledata(int data)  //删除data的元素
{
  Slnode *del = findnode(data);  //需要删除的结点
  if(!del) return;  //找不到该结点

  //std::cout<<"找到该结点,del->level:"<<del->level<<std::endl;

  Slnode *temp = root;
  for(unsigned i =del->level,j = root->level;j-i;i++)
   temp = temp->down;                   //先把temp移动到和del结点平齐的level

  //std::cout<<"目前temp->level:"<<temp->level<<std::endl;

  while(del)
  {
      Slnode *temp2 = temp;
      while(temp2->next->data!=INT_MAX)
      {
          if(temp2->next==del)
            {
              temp2->next = del->next;
              Slnode *temp3 = del;
              del = del->down;
              delete temp3;
              break;
            }
        temp2 = temp2->next;
      }
   temp = temp->down;
  // std::cout<<"下移"<<std::endl;
  }

nodecount--;
}


void PrBottom()  //显示底层元素排列情况
{
  Slnode *temp = root;
  while(temp->down)
    temp = temp->down;
  std::cout<<"底层元素排列:";
  while(temp->next&&temp->next->data!=INT_MAX)
  {
      temp = temp->next;
      std::cout<<temp->data<<" ";
  }
}


void Prtotol()  //显示所有层元素排列情况
{
  Slnode *temp = root;
  while(temp)
  {
      Slnode *temp2 = temp;
      while(temp2->next && temp2->next->data!=INT_MAX)
      {
         temp2 = temp2->next;
         std::cout<<temp2->data<<" ";
      }
       std::cout<<std::endl;
   temp = temp->down;
  }
}



};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值