C++ :跳表数据结构的实现原理
所谓的跳表,就是在有序链表的基础上加上索引层,在索引层的基础上还可以再加索引层,从而提高链表的查询效率,一般情况下也可以提高插入和删除效率。
-----------------------------------------------------------------------
目录
一、跳表的数据结构
二、重建索引
三、根据位置确定数据节点
四、根据元素data信息来查询元素位置
五、插入和删除
一、跳表的数据结构
跳表由索引层链表和数据层链表组成,数据层链表由 next指针部分和数据部分组成。索引层链表由 数据部分、索引指针部分、next指针部分三部分组成,其中数据部分值和索引指针指向节点的值保持一致。最底层的索引指针指向数据层链表节点,其它层索引指针指向低层的索引链表节点。
template<class ElemType>class SkipList {public:class IndexStruct{public:ElemType position() const;void position(ElemType position);bool operator <(IndexStruct a);bool operator ==(IndexStruct a);bool operator >(IndexStruct a);IndexStruct& operator =(const IndexStruct & a);IndexStruct(ElemType position, const boost::shared_ptr<LinkList<ElemType>> &pointer);IndexStruct(){}public: struct U{boost::shared_ptr<LinkList<IndexStruct>> indexPointer;boost::shared_ptr<LinkList<ElemType>> dataPointer;}pointer_;const U &pointer() const;void pointer(const U &pointer);ElemType position_; //datalist的索引位};explicit SkipList(Integer skipstep = 2):skipstep_(skipstep+1){}public:int findIndexListPosition(int indexlevel,ElemType dataPos,boost::shared_ptr<LinkList<IndexStruct>>& idxlist);void rebuildIndex(ElemType startElem );int findPosByElem(ElemType elem);void removeByPos(Size pos);boost::shared_ptr<LinkList<ElemType>> findNodeByPos(Size pos);void removeByElem(ElemType e);void insertElem(ElemType e,bool isRebuildIndex = false);boost::shared_ptr<LinkList<ElemType>>findDataNode(ElemType elem,bool isAccurate = true);boost::shared_ptr<LinkList<IndexStruct>> findIndexNode(int indexlevel,ElemType dataPos);const std::vector<boost::shared_ptr<LinkList<IndexStruct>>> &indexLinklist() const{return indexLinklist_;};void indexLinklist(const std::vector<boost::shared_ptr<LinkList<IndexStruct>>> &indexLinklist){indexLinklist_=indexLinklist;};const boost::shared_ptr<LinkList<ElemType>> &dataLinklist() const{return dataLinklist_;};void dataLinklist(const boost::shared_ptr<LinkList<ElemType>> &dataLinklist){dataLinklist_=dataLinklist;if (dataLinklist_ ->next){rebuildIndex(dataLinklist_->next->data);}else{indexLinklist_.clear();}};private:std::vector< boost::shared_ptr<LinkList<IndexStruct>>> indexLinklist_;//索引链表,数据是地址boost::shared_ptr<LinkList<ElemType>> dataLinklist_; //有序数据链表LinkListUtil<ElemType> dataListUtil_;LinkListUtil<IndexStruct> indexListUtil_;const Integer skipstep_;};
二、重建索引
已知有数据层链表dataLinkList ,长度为 n,那么第 level层需要建立的索引数是 datalistsize /pow(skipstep_,level ) 个,每隔skipstep个数据节点就建立一个索引,直到第level层需要建立的节点数是0就不再键索引。在此过程中,如果层级要大于原有索引层级需要扩充索引层,否则再原来索引层进行修改。
/*** <p>从第数据链表的startElem开始重建立链表* @tparam ElemType* @param startElem*/
template<class ElemType>
void SmartDongLib::SkipList<ElemType>::rebuildIndex(ElemType startElem) {//获取数据总数int datalistsize = dataListUtil_.listLenth(dataLinklist_);//要重建数据索引的个数
// int rebuldDataCount = datalistsize - startIndex +1;//索引层应建立索引的节点数int indexlevelCount = datalistsize / skipstep_;int indexlevel=0;while (indexlevelCount !=0){//如果层级要大于 indexLinklist_.size(),需要扩充indexList,否则再原来的基础上修改,还需要判断是不是第0索引层if(indexlevel >= indexLinklist_.size()){boost::shared_ptr<LinkList<IndexStruct>> currentIndexList (new LinkList<IndexStruct>());//头指针也进行关联if (indexlevel ==0){currentIndexList->data.pointer_.dataPointer = dataLinklist_;
// currentIndexList->data.position_ =dataLinklist_->data;}else{currentIndexList->data.pointer_.indexPointer = indexLinklist_[indexlevel-1];
// currentIndexList->data.position_ =indexLinklist_[indexlevel-1]->data.position_;}bool isfirst = true;boost::shared_ptr<LinkList<ElemType>> linkdataNode;boost::shared_ptr<LinkList<IndexStruct>> linkindexNode;//扩展 indexlevel 层的后面的索引for (int i = 1; i <=indexlevelCount; ++i) {
// boost::shared_ptr<LinkList<IndexStruct>> currentIndexNode (new LinkList<IndexStruct>);IndexStruct currentIndexNode;//第0索引层指向data数据,其他指向下层索引数据。优化:第一次从头节点确定指向的位置,之后再此基础上在+上skipstep_if (indexlevel == 0) {if (isfirst){linkdataNode = dataListUtil_.listGetNode(dataLinklist_,i * skipstep_);isfirst= false;}else{linkdataNode = dataListUtil_.listGetNode(linkdataNode, skipstep_);}currentIndexNode.position_ =linkdataNode->data;currentIndexNode.pointer_.dataPointer = linkdataNode;}else{if (isfirst){linkindexNode =indexListUtil_.listGetNode(indexLinklist_[indexlevel - 1], i * skipstep_);isfirst= false;}else{linkindexNode =indexListUtil_.listGetNode(linkindexNode, skipstep_);}currentIndexNode.position_ =linkindexNode->data.position_;currentIndexNode.pointer_.indexPointer = linkindexNode;}indexListUtil_.listOrderInsert(currentIndexList,currentIndexNode);}indexLinklist_.push_back(currentIndexList);} else{//如果在原来的索引层上进行修改,那么确认要修改的索引节点进行重建boost::shared_ptr<LinkList<IndexStruct>> currentIndexList=indexLinklist_[indexlevel];//找到startElem前一个元素的位置boost::shared_ptr<LinkList<IndexStruct>> startIndexNode;int startIdx = findIndexListPosition(indexlevel, startElem,startIndexNode);//重键startIndexNode之后的索引startIndexNode->next = NULL;boost::shared_ptr<LinkList<ElemType>> linkdataNode;boost::shared_ptr<LinkList<IndexStruct>> linkindexNode;bool isfirst = true;//第indexlevel层从startIdx开始重建索引for (int i = startIdx+1; i <=indexlevelCount; ++i){
// boost::shared_ptr<LinkList<IndexStruct>> currentIndexNode (new LinkList<IndexStruct>);
// LinkList<IndexStruct> currentIndexNode;IndexStruct currentIndexNode;//优化:第0索引层指向data数据,其他指向下层索引数据,第一次从头节点确定指向的位置,之后再此基础上在+上skipstep_if (indexlevel == 0) {if (isfirst){linkdataNode = dataListUtil_.listGetNode(dataLinklist_,i * skipstep_);isfirst= false;}else{linkdataNode = dataListUtil_.listGetNode(linkdataNode, skipstep_);}currentIndexNode.position_ =linkdataNode->data;currentIndexNode.pointer_.dataPointer = linkdataNode;}else{if (isfirst){linkindexNode =indexListUtil_.listGetNode(indexLinklist_[indexlevel - 1], i * skipstep_);isfirst= false;}else{linkindexNode =indexListUtil_.listGetNode(linkindexNode, skipstep_);}currentIndexNode.position_ =linkindexNode->data.position_;currentIndexNode.pointer_.indexPointer = linkindexNode;}indexListUtil_.listOrderInsert(currentIndexList,currentIndexNode);}}indexlevel++;indexlevelCount /= skipstep_;}}
三、根据位置确定数据节点
在level层移动一次next 对应的数据层节点数增加pow(skipstep_,currentIndexlevel)位置。
/*** <p>获取节点(已优化)* @tparam ElemType* @param pos data的位置* @return 获取pos对应的元素节点*/
template<class ElemType>
boost::shared_ptr<SmartDongLib::LinkList<ElemType>> SmartDongLib::SkipList<ElemType>::findNodeByPos(Size pos) {int indexlistsize = indexLinklist_.size();int currentIndexlevel = indexlistsize-1;boost::shared_ptr<LinkList<IndexStruct>> currentIndexNode = indexLinklist_[currentIndexlevel];int currentPos = 0;int posIncrement =1;boost::shared_ptr<LinkList<ElemType>> ret = dataLinklist_;while(currentPos <= pos && currentIndexlevel >=0){posIncrement = std::pow(skipstep_,currentIndexlevel + 1);if ( currentIndexNode->next!=NULL && currentPos + posIncrement <=pos ){//如果查在后面currentIndexNode=currentIndexNode->next;currentPos +=posIncrement;}else{//如果当前层确定了位置,就下一层直到第indexlevel结束if ( currentIndexlevel == 0 ){ret = currentIndexNode->data.pointer_.dataPointer;currentIndexlevel --;break;}else{currentIndexNode = currentIndexNode->data.pointer_.indexPointer;currentIndexlevel --;}}}while (pos - currentPos >0 && currentIndexlevel<0){ret = ret->next;currentPos ++ ;}return ret;
}
四、根据元素data信息来查询元素位置
/*** <p>根据元素寻找在datalinklist中的位置(已优化)* @tparam ElemType* @param elem* @return 位找到是-1 ,头节点是第0个位置*/
template<class ElemType>
int SmartDongLib::SkipList<ElemType>::findPosByElem(ElemType elem) {int indexlistsize = indexLinklist_.size();int currentIndexlevel = indexlistsize-1;boost::shared_ptr<LinkList<IndexStruct>> idxlist=indexLinklist_[currentIndexlevel];int pos = 0;while (currentIndexlevel >= 0){if ( idxlist->next && idxlist->next->data.position() <= elem ){//如果查在后面idxlist=idxlist->next;pos =pos + std::pow(skipstep_,currentIndexlevel +1 );}else{//如果当前层确定了位置,就下一层直到第indexlevel结束if ( currentIndexlevel == 0 ){break;}else{idxlist = idxlist->data.pointer_.indexPointer;currentIndexlevel --;}}}boost::shared_ptr<LinkList<ElemType>> dataNode = idxlist->data.pointer_.dataPointer;if (dataNode ->data == elem){return pos;} else{int rslt =dataListUtil_.listGetIndex(dataNode,elem);if (rslt == -1 )return -1;elsereturn pos + dataListUtil_.listGetIndex(dataNode,elem);}
}
五、插入和删除
查询到要插入的节点位置后,进行普通有序链表的插入和删除即可
C++ :跳表数据结构的实现原理相关推荐
- 二叉树 跳表_面试题之跳表
本文主要讲解跳表的原理.代码实现以及与之相关的常见面试题. 跳表本质上是一种查找结构,相比于平衡树,不仅实现简单,而且插入.删除.查找的时间复杂度均为O(logN).跳表其实就是链表,只是对有序的链表 ...
- skiplist跳表的 实现
文章目录 前言 跳表结构 时间复杂度 空间复杂度 高效的动态插入和删除 跳表索引的动态更新 总结 详细实现 前言 rocksdb 的memtable中默认使用跳表数据结构对有序数据进行的管理,为什么呢 ...
- 跳表SkipList
1.聊一聊跳表作者的其人其事 2. 言归正传,跳表简介 3. 跳表数据存储模型 4. 跳表的代码实现分析 5. 论文,代码下载及参考资料 <1>. 聊一聊作者的其人其事 跳表是由Will ...
- 面试官:为何Redis使用跳表而非红黑树实现SortedSet?
知道跳表(Skip List)是在看关于Redis的书的时候,Redis中的有序集合使用了跳表数据结构.接着就查了一些博客,来学习一下跳表.后面会使用Java代码来简单实现跳表. 什么是跳表 跳表由W ...
- 【恋上数据结构】跳表(Skip List)原理及实现
跳表(Skip List) 引出跳表 跳表介绍 跳表原理及实现 使用跳表优化链表 跳表基础结构 跳表的搜索 跳表的添加.删除 跳表的层数 跳表的复杂度分析 跳表 - 完整源码 数据结构与算法笔记:恋上 ...
- 数据结构算法动图识记_【数据结构与算法】用动图解说数组、链表、跳表原理与实现...
「初」前言 在学习数据结构与算法的过程中,感觉真的是一入算法深似海,但是越学越觉得有趣.不过我们会发现在终身学习的过程中,我们都是越学越多,不知的也越来越多,但是更渴望认知更多的知识,越是对知识感兴趣 ...
- 数据结构与算法 / 跳表
一.诞生原因 解决链表查询时耗时过长的问题. 二.基本信息 英文全称:Skip List . 链表 + 多级索引(链表) = 跳表 三.原理说明 顾名思义,跳表的查询是在多个链表之间跳跃查询的,其路线 ...
- 二叉树 跳表_漫谈 LevelDB 数据结构(一):跳表(Skip List)
早对 LevelDB 有所耳闻,这次心血来潮结合一些资料粗略过了遍代码,果然名不虚传--绝对是不世出的工艺品!如果你对存储感兴趣.如果你想优雅使用C++.如果你想学习如何架构项目,都推荐来观摩一下.谷 ...
- 数据结构进阶篇-跳表
大家想必都知道,数组和链表的搜索操作的时间复杂度都是O(N)的,在数据量大的时候是非常耗时的.对于数组来说,我们可以先排序,然后使用二分搜索,就能够将时间复杂度降低到O(logN),但是有序数组的插入 ...
最新文章
- SpringBatch配置数据库
- mongodb导出导入实例记录
- 用Linux虚拟机手工编译安装Apache
- 浓烟滚滚!某市联通集体断网,谁的锅?
- 制作多域名(SAN/UCC)CSR(证书请求文件)
- 机器学习新论文推荐-(成对关系约束的非负矩阵分解)
- java核心标签库,16.JSTL标签库(我的JavaEE笔记)
- 一张纸折多少次可以变成珠穆朗玛峰那么高?
- Java:AspectJ的异常翻译
- css实现文字过长省略显示
- Leetcode: Binary Tree Inorder Traversal
- 『高级篇』docker之开发用户服务EdgeService(13)
- HDU1846 Brave Game【巴什博弈】
- GIS专业书籍、文档、数据、网站、工具等干货
- beamer插入参考文献并引用(BibTex)
- eclipse安装反编译软件jd-gui
- 计算机与宽带路由的连接步骤,宽带拨号和设置路由器步骤【图】
- GCD中的dispatch_barrier_async函数的使用(栅栏函数)
- CFS调度下带宽控制(Bandwidth Control)
- 致远oa系统unix 服务器,致远oa如何设置服务器地址