Двусвязный список со списком пропуска для вставки отсортированным способом

Я читал о списках пропуска в Интернете, и я только что понял, как он работает с разными структурами данных и всем остальным. Но я действительно хочу реализовать список пропуска с двусвязным списком, поскольку я хочу отсортировать двусвязный список во время вставки. Означает, что когда элемент вставлен в это время, он должен быть вставлен только в отсортированном виде.

Здесь я реализую метод вставки данных в двусвязный список отсортированным способом, но это занимает много времени, чтобы вставить данные и составить список отсортированным способом, когда количество элементов очень велико.

Скажите, пожалуйста, как я могу добавить алгоритм пропуска списка в существующую функцию, или мне придется переписать все заново? Любая помощь в реализации будет оценена

Вот код:

void DoubleList::addSorted(int value)
{
    IDoubleNode * tempNode = new DoubleNode();
    tempNode->setValue(value);
    // if double link list is empty 
    if(getHead() == NULL)
    {
        // temp node already has NULL value in next and prev.
        setHead(tempNode);
        setTail(tempNode);
    }
    else if(value <= getHead()->getValue())
    {
        tempNode->setNext(getHead());// set tempnode next as current head.
        tempNode->setPrev(getHead()->getPrev()); // set previous
        getHead()->setPrev(tempNode); // set previous pointer of head to tempnode which we just inserted
        setHead(tempNode); // set head
        getHead()->setPrev(NULL);// for safer side. we already done this.
    }
    else
    {
        int found = 0;
        IDoubleNode *currNode = getHead();
        while(currNode->getNext() != NULL && found == 0)
        {
            if(currNode->getNext()->getValue() > tempNode->getValue())
            {
                found = 1;
            }
            else
            {
                currNode = currNode->getNext();
            }
        }
        if(found)
        {
            tempNode->setNext(currNode->getNext());
            currNode->getNext()->setPrev(tempNode);
            currNode->setNext(tempNode);
            tempNode->setPrev(currNode);
        }
        else
        {
            currNode->setNext(tempNode);
            tempNode->setPrev(currNode);
            tempNode->setNext(NULL);
            setTail(tempNode);
        }
    }
}

person sam_k    schedule 14.02.2015    source источник


Ответы (2)


Прелесть skiplist в том, что он сортирует элементы данных, а также предлагает временную сложность вставки и удаления o (log n). Чтобы сделать его более понятным, представьте, что в вашем связанном списке есть ярлыки или якоря, так что вам не нужно перемещаться по всему списку, чтобы найти позицию для вставки элемента. Вы просто следуете якорям, поэтому это список с двумя ссылками и якорями быстрого доступа.

Что касается реализации, если вы не собираетесь использовать список пропуска для многопоточного доступа, то реализовать его становится тривиально. Нет причин комбинировать пропускаемый список с двусвязным списком, но вы можете реализовать skiplist как двусвязный список.

Посмотрите на http://www.sanfoundry.com/cpp-program-implement-skip-list/

person ivanw    schedule 14.02.2015
comment
Спасибо за ответ. Я предполагаю, что возникнет проблема для установки prev каждого узла в двусвязном списке. как это мы можем управлять в списке пропуска - person sam_k; 15.02.2015
comment
какова мотивация наличия у скиплиста предварительных указателей? - person ivanw; 15.02.2015
comment
Я реализую двусвязный список, поэтому он должен иметь указатели prev, потому что мой модульный тест также будет проверять его в обратном порядке. Верно это или нет. - person sam_k; 15.02.2015
comment
Вы можете посмотреть на этот пример реализации skip-list с обратными указателями. coderslexicon.com/ Надеюсь, что сможет help, это не добавляет большой сложности, но вам придется иметь дело с гораздо большим количеством указателей при каждом удалении или вставке узлов. - person ivanw; 16.02.2015

Я надеюсь, это поможет вам.

#ifndef SkipList_h
#define SkipList_h
///////////////////////////////////////////////////////////////////////////////

template<typename K, typename V, int MAXLEVEL>
class SkipListNode
{

public:
    SkipListNode()
    {
        for(int i=1; i<=MAXLEVEL;i++){
            next[i] = nullptr;
            prev[i] = nullptr;
        }
    }

    SkipListNode(K searchKey):key(searchKey)
    {
        for(int i=1; i<=MAXLEVEL;i++){
            next[i] = nullptr;
            prev[i] = nullptr;
        }
    }

    SkipListNode(K searchKey, V val):key(searchKey),value(val)
    {
        for(int i=1; i<=MAXLEVEL;i++){
            next[i] = nullptr;
            prev[i] = nullptr;
        }
    }

    // custom memory management
   // static void * operator new(size_t size);

  //  static void operator delete( void *deadObject, size_t size );


    K key;
    V value;
    SkipListNode<K, V, MAXLEVEL>* next[MAXLEVEL+1];
    SkipListNode<K, V, MAXLEVEL>* prev[MAXLEVEL+1];
private:
   // static MemoryPool<SkipListNode> memPool; // memory pool for SkipListNode
};

// template<typename K, typename V, int MAXLEVEL>
// MemoryPool< SkipListNode<K, V, MAXLEVEL> > SkipListNode<K, V, MAXLEVEL>::memPool;

// template<typename K, typename V, int MAXLEVEL>
// inline void * SkipListNode<K, V, MAXLEVEL>::operator new ( size_t size )
// {
//     return memPool.allocate();
// }

// template<typename K, typename V, int MAXLEVEL>
// inline void SkipListNode<K, V, MAXLEVEL>::operator delete( void *p, size_t size )
 //{
 //    memPool.deallocate( static_cast<SkipListNode<K, V, MAXLEVEL> *>(p) );
 //}


///////////////////////////////////////////////////////////////////////////////

template<typename K, typename V, int MAXLEVEL = 16>
class SkipList
{
public:
    typedef K keyType;
    typedef V ValueType;
    typedef SkipListNode<K, V, MAXLEVEL> NodeType;
    const int maxLevel;

    SkipList(K min_key, K max_key)
                                :pHeader(nullptr), pTail(nullptr),
                                maxCurrLevel(1), maxLevel(MAXLEVEL),
                                minKey(min_key), maxKey(max_key)
    {
        pHeader = new NodeType(minKey);
        pTail = new NodeType(maxKey);

        for( int i = 1; i<=MAXLEVEL; i++){
            pHeader->next[i] = pTail;
            pTail->prev[i] = pHeader;
        }
    }

    virtual ~SkipList()
    {

        delete pHeader;
        delete pTail;
    }

    void removeAll()
    {
        NodeType* curNode = pHeader->next[1];
        while(curNode != pTail){
            NodeType* temp = curNode;
            curNode = curNode->next[1];
            delete temp;
        }
    }

    std::string printList()
    {
        std::stringstream sstr;
        NodeType* currNode = pHeader->next[1];
        while ( currNode != pTail ) {
            sstr << "(" << currNode->key << "," << currNode->value << ")" << std::endl;
            currNode = currNode->next[1];
        }
        return sstr.str();
    }

    NodeType* insert( K searchKey, V newValue );

    void removeKey( K searchKey );
    void removeKey( NodeType* curNode );

    NodeType* search(const K& key, NodeType** prev   );

private:
    K minKey;
    K maxKey;
    int maxCurrLevel;
    SkipListNode<K, V, MAXLEVEL>* pHeader;
    SkipListNode<K, V, MAXLEVEL>* pTail;

    double uniformRandom()
    {
        return rand() / double(RAND_MAX);
    }

    int randomLevel() {
        int level = 1;
        double p = 0.5;
        while ( uniformRandom() < p && level < MAXLEVEL ) {
            level++;
        }
        return level;
    }
};

template<typename K, typename V, int MAXLEVEL>
typename SkipList<K, V, MAXLEVEL>::NodeType* SkipList<K, V, MAXLEVEL>::search(const K& searchKey, NodeType** prev )
{
    NodeType* currNode = nullptr;

    currNode = pHeader;
    for (int level=maxCurrLevel; level>=1; level--) {
        // Start our search at previous level's predecessor

        while (currNode->next[level]->key < searchKey) {
            currNode = currNode->next[level];

        }
        if ( prev != nullptr) {
            prev[level] = currNode;
        }

        //currNode = currNode->next[level];
        /*
        if ( next != nullptr) {
            next[level] = currNode;
        }*/
    }

    currNode = currNode->next[1];
    return currNode;
}

template<typename K, typename V, int MAXLEVEL>
typename SkipList<K, V, MAXLEVEL>::NodeType*  SkipList<K, V, MAXLEVEL>::insert( K searchKey, V newValue )
{
    SkipListNode<K, V, MAXLEVEL>** next = nullptr;
    SkipListNode<K, V, MAXLEVEL>* prev[MAXLEVEL];

    auto foundNode = search(searchKey, prev);


    int newLevel = randomLevel();
    //std::cout<< "Level: "<<newLevel<< std::endl;

    if ( newLevel > maxCurrLevel ) {
        for ( int level = maxCurrLevel+1; level <= newLevel; level++ ) {
            prev[level] = pHeader;
        }

        maxCurrLevel = newLevel;
    }

    NodeType* curNode = new NodeType(searchKey, newValue);

    for ( int level = 1; level<=maxCurrLevel; level++ ) {
        curNode->next[level] = prev[level]->next[level];
        curNode->prev[level] = prev[level];
        prev[level]->next[level]->prev[level] = curNode;
        prev[level]->next[level] = curNode;
    }
    return curNode;
}

template<typename K, typename V, int MAXLEVEL>
void SkipList<K, V, MAXLEVEL>::removeKey( K searchKey)
{

    SkipListNode<K, V, MAXLEVEL>** prev1 = nullptr;

    auto curNode = search(searchKey, prev1);


    //std::cout<<curNode <<" -> "<< curNode->key<< std::endl;
    if ( curNode && curNode->key == searchKey ) {

        auto prev = curNode->prev;

        for ( int level = 1; level<=maxCurrLevel; level++ ) {

            if ( prev[level]->next[level] != curNode ) {
                break;
            }

            prev[level]->next[level] = curNode->next[level];
            curNode->next[level]->prev[level] = prev[level];
        }

        delete curNode;

        while ( maxCurrLevel > 1 && pHeader->next[maxCurrLevel] == pTail) {
            maxCurrLevel--;
        }

        //std::cout << "maxCurrLevel: "<<maxCurrLevel<<std::endl;
    }

}


template<typename K, typename V, int MAXLEVEL>
void SkipList<K, V, MAXLEVEL>::removeKey( typename SkipList<K, V, MAXLEVEL>::NodeType* curNode )
{
    if ( curNode && curNode == curNode->next[1]->prev[1] && curNode == curNode->prev[1]->next[1] ) {
       // std::cout<<curNode <<" -> "<< curNode->key<< std::endl;

        auto prev = curNode->prev;

        for ( int level = 1; level<=maxCurrLevel; level++ ) {

            if ( prev[level]->next[level] != curNode ) {
                break;
            }

            prev[level]->next[level] = curNode->next[level];
            curNode->next[level]->prev[level] = prev[level];
        }

        delete curNode;

        while ( maxCurrLevel > 1 && pHeader->next[maxCurrLevel] == pTail ) {
            maxCurrLevel--;
        }
    }
}


#endif
person ivanw    schedule 24.02.2015