跳跃表的定义及实现
2017-08-16 22:52
218 查看
跳跃表:
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指针指向最高层的第一个元素。
基于以上,我对这个跳跃表的理解,认为这种数据结构 主要用于存储拥有大量结点,并且需要增删减查功能的链表。建立的跳跃表结点结构体:
每个结点都需要保存当前的数据和层数,以及横向(next)以及纵向(down)指针信息。
边写才边发现,其实我用于存储的 int data,应该要作为数据索引更改为 int key,并且不允许插入相同的key,然后在结点中再增加一项typedef data作为需要存储的数据才是一个正确的跳跃表(感觉有点象哈希了hahah),
不过由于时间原因,我就先放这了,大略思想应该是对的。
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; } } };
相关文章推荐
- VC实现java定义的接口的一些方法
- PHP实现生成vcf vcard文件功能类定义与使用方法详解【附demo源码下载】[原创]_php技巧_脚本之家
- 定义栈的数据结构,请在该类型中实现一个能够得到栈最小元素的min函数。
- C++实例 静态成员的引入——静态数据成员的定义、调用,静态成员函数的实现、调用。
- c++接口定义及实现举例
- 线程基础 第一篇:线程的定义、状态、属性、简单实现线程
- 协议的定义,实现,使用
- Android实现一个自己定义相机的界面
- 实现C语言的拷贝函数且将复制后的字符串逆序,不能使用库函数,不能定义其他的变量。
- 【第十二章】零配置 之 12.3 注解实现Bean定义、12.4基于Java类定义Bean配置元数据 ——跟我学spring3
- 实现C语言的拷贝函数且将复制后的字符串逆序,不能使用库函数,不能定义其他的变量。
- java包 + 接口的定义与实现接口抽象方法 + 并发视频
- UILable实现按照文字多少定义大小
- 第五章 工作流定义工具的设计与实现(六)
- MFC 如何定义头文件和实现分离
- 理解数组,结构 ,函数指针,指针函数,数组指针,指针数组,结构指针的定义和实现
- 通过定义BaseActivity来实现项目中代码重用,重写setContentView实现多个Activity部分UI布局相同
- C++ 实现动态定义三维内的数组
- Android 内部跳转URi协议的定义和实现方案
- WPF窗体程序中实现响应系统热键所用到的键值定义