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;
        else
            return  pos + dataListUtil_.listGetIndex(dataNode,elem);
    }
}

五、插入和删除

       查询到要插入的节点位置后,进行普通有序链表的插入和删除即可

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值