所谓的跳表,就是在有序链表的基础上加上索引层,在索引层的基础上还可以再加索引层,从而提高链表的查询效率,一般情况下也可以提高插入和删除效率。

-----------------------------------------------------------------------

目录

一、跳表的数据结构

二、重建索引

三、根据位置确定数据节点

四、根据元素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++ :跳表数据结构的实现原理相关推荐

  1. 二叉树 跳表_面试题之跳表

    本文主要讲解跳表的原理.代码实现以及与之相关的常见面试题. 跳表本质上是一种查找结构,相比于平衡树,不仅实现简单,而且插入.删除.查找的时间复杂度均为O(logN).跳表其实就是链表,只是对有序的链表 ...

  2. skiplist跳表的 实现

    文章目录 前言 跳表结构 时间复杂度 空间复杂度 高效的动态插入和删除 跳表索引的动态更新 总结 详细实现 前言 rocksdb 的memtable中默认使用跳表数据结构对有序数据进行的管理,为什么呢 ...

  3. 跳表SkipList

    1.聊一聊跳表作者的其人其事 2. 言归正传,跳表简介 3. 跳表数据存储模型 4. 跳表的代码实现分析 5. 论文,代码下载及参考资料 <1>. 聊一聊作者的其人其事  跳表是由Will ...

  4. 面试官:为何Redis使用跳表而非红黑树实现SortedSet?

    知道跳表(Skip List)是在看关于Redis的书的时候,Redis中的有序集合使用了跳表数据结构.接着就查了一些博客,来学习一下跳表.后面会使用Java代码来简单实现跳表. 什么是跳表 跳表由W ...

  5. 【恋上数据结构】跳表(Skip List)原理及实现

    跳表(Skip List) 引出跳表 跳表介绍 跳表原理及实现 使用跳表优化链表 跳表基础结构 跳表的搜索 跳表的添加.删除 跳表的层数 跳表的复杂度分析 跳表 - 完整源码 数据结构与算法笔记:恋上 ...

  6. 数据结构算法动图识记_【数据结构与算法】用动图解说数组、链表、跳表原理与实现...

    「初」前言 在学习数据结构与算法的过程中,感觉真的是一入算法深似海,但是越学越觉得有趣.不过我们会发现在终身学习的过程中,我们都是越学越多,不知的也越来越多,但是更渴望认知更多的知识,越是对知识感兴趣 ...

  7. 数据结构与算法 / 跳表

    一.诞生原因 解决链表查询时耗时过长的问题. 二.基本信息 英文全称:Skip List . 链表 + 多级索引(链表) = 跳表 三.原理说明 顾名思义,跳表的查询是在多个链表之间跳跃查询的,其路线 ...

  8. 二叉树 跳表_漫谈 LevelDB 数据结构(一):跳表(Skip List)

    早对 LevelDB 有所耳闻,这次心血来潮结合一些资料粗略过了遍代码,果然名不虚传--绝对是不世出的工艺品!如果你对存储感兴趣.如果你想优雅使用C++.如果你想学习如何架构项目,都推荐来观摩一下.谷 ...

  9. 数据结构进阶篇-跳表

    大家想必都知道,数组和链表的搜索操作的时间复杂度都是O(N)的,在数据量大的时候是非常耗时的.对于数组来说,我们可以先排序,然后使用二分搜索,就能够将时间复杂度降低到O(logN),但是有序数组的插入 ...

最新文章

  1. SpringBatch配置数据库
  2. mongodb导出导入实例记录
  3. 用Linux虚拟机手工编译安装Apache
  4. 浓烟滚滚!某市联通集体断网,谁的锅?
  5. 制作多域名(SAN/UCC)CSR(证书请求文件)
  6. 机器学习新论文推荐-(成对关系约束的非负矩阵分解)
  7. java核心标签库,16.JSTL标签库(我的JavaEE笔记)
  8. 一张纸折多少次可以变成珠穆朗玛峰那么高?
  9. Java:AspectJ的异常翻译
  10. css实现文字过长省略显示
  11. Leetcode: Binary Tree Inorder Traversal
  12. 『高级篇』docker之开发用户服务EdgeService(13)
  13. HDU1846 Brave Game【巴什博弈】
  14. GIS专业书籍、文档、数据、网站、工具等干货
  15. beamer插入参考文献并引用(BibTex)
  16. eclipse安装反编译软件jd-gui
  17. 计算机与宽带路由的连接步骤,宽带拨号和设置路由器步骤【图】
  18. GCD中的dispatch_barrier_async函数的使用(栅栏函数)
  19. CFS调度下带宽控制(Bandwidth Control)
  20. 致远oa系统unix 服务器,致远oa如何设置服务器地址

热门文章

  1. 大数据审计护航现代金融体系构建
  2. 漫游Kafka之过期数据清理
  3. 【技术干货】浏览器工作原理和常见WEB攻击 (下)
  4. XSS 前端防火墙 —— 天衣无缝的防护
  5. npm run build,start
  6. Scala Collection体系介绍
  7. go使用for...range遍历数组
  8. jenkins 发送邮件插件Email Extension Template Plugin配置及script pipeline完整脚本
  9. 限流算法——漏桶算法和令牌桶算法介绍
  10. JVM调优:常见垃圾回收器及常见组合