C ++:ジャンプテーブルのデータ構造の実現原理

  いわゆるジャンプリスト、順序付けられたリンクリストに基づいてインデックスレイヤーを追加することであり、インデックスレイヤーに基づいてインデックスレイヤーを追加することで、リンクリストのクエリ効率を向上させることができます。挿入と削除の効率も向上します。

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

目次

1つは、ジャンプテーブルのデータ構造です。

次に、インデックスを再構築します

3、場所に応じてデータノードを決定します

第四に、要素データ情報に従って要素の位置を照会します

5、挿入と削除


1つは、ジャンプテーブルのデータ構造です。

      ジャンプテーブルは、インデックスレイヤーリンクリストとデータレイヤーリンクリストで構成され、データレイヤーリンクリストは、次のポインタ部分とデータ部分で構成されます。インデックスレイヤーのリンクリストは、データ部分、インデックスポインター部分、次のポインター部分の3つの部分で構成されます。データ部分の値は、インデックスポインターが指すノードの値と一致します。最下位のインデックスポインタはデータ層のリンクリストノードを指し、他の層のインデックスポインタは下位層のインデックスリンクリストノードを指します。

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_;
    };

次に、インデックスを再構築します

       長さnのデータレイヤーリンクリストdataLinkListがあることがわかっている場合、レベルレベルで確立する必要のあるインデックスの数はdatalistsize / pow(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_;
    }

}

3、場所に応じてデータノードを決定します

レベルレイヤーで次に対応するデータレイヤーノード番号を1回移動して、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;
}

第四に、要素データ情報に従って要素の位置を照会します

/**
 * <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);
    }
}

5、挿入と削除

       挿入するノードの位置を照会した後、通常の順序付きリンクリストを挿入および削除します。

おすすめ

転載: blog.csdn.net/superSmart_Dong/article/details/111876680