跳表的简单原理与泛型实现

什么是跳表

如下所示就是一个随机生成的跳跃表。每一个结点不单单只包含指向下一个结点的指针,可能包含很多个指向后续结点的指针,这样就可以跳过一些不必要的结点,从而加快查找、删除等操作。对于一个链表内每一个结点包含多少个指向后续元素的指针,这个过程是通过一个随机函数生成器得到。

跳表是一个随机化的数据结构,实质就是一种可以进行二分查找的有序链表。跳表在原有的有序链表上面增加了多级索引,通过索引来实现快速查找。跳表不仅能提高搜索性能,同时也可以提高插入和删除操作的性能。插入/删除/搜索 都是 O(log n) 。

跳表是一个随机化的数据结构,可以被看做二叉树的一个变种,它在性能上和红黑树,AVL树不相上下,但是跳表的原理非常简单,目前在Redis和LeveIDB中都有用到。

时间复杂性

当跳表中有n个元素时,搜索、插入、删除操作的复杂性均为O(n+MaxLevel)。在最坏情况下,可能只有一个MaxLevel级元素,且余下的所有元素均在0级链上。i>0时,在i级链上花费的时间为(MaxLevel),而在0级链上花费的时间为O(n)。尽管最坏情况下的性能较差,但跳表仍不失为一种有价值的数据描述方法。其每种操作(搜索、插入、删除)的平均复杂性均为O(logn),

空间复杂性

至于空间复杂性,注意到最坏情况下所有元素都可能是MaxLevel级,每个元素都需要

MaxLevel+1个指针。因此,除了存储n个元素(也就是n*sizeof(element)),还需要存储链指针(所需空间为O(n*MaxLevel))。不过,一般情况下,只有n*p个元素在1级链上,n*p2个元素在2级链上,n*pi在i级链上。因此指针域的平均值(不包括头尾节点的指针)是n/(1-p)。因此虽然最坏情况下空间需求比较大,但平均的空间需求并不大。当p=0.5时,平均空间需求(加上n个节点中的指针)大约是2n个指针的空间。

性能比较

实现代码如下

tg_skiplist.h

#ifndef TG_SKIPLIST_H
#define TG_SKIPLIST_H

#include <random>
#include <memory>
#include <vector>
#include<array>
#include<functional>

template<typename KeyType,typename ValueType>
class tg_skiplist
{
#define CONST_MAX_LEVEL 31

    struct inner_node
    {
        inner_node(KeyType key, ValueType value, int level):key(key),value(value)
        {
            forward.reserve(level+1);
            for(int i = 0; i < level+1; i++)
            {
                forward[i] = nullptr;
            }
        }

        KeyType key;
        ValueType value;
        std::vector<std::shared_ptr<inner_node>> forward;
    };
    typedef std::shared_ptr<inner_node> inner_node_ptr;

public:
    tg_skiplist():_level(0),_size(0)
    {
        KeyType k;
        ValueType v;

        _head = std::make_shared<inner_node>(k, v, CONST_MAX_LEVEL-1);
    }

    ~tg_skiplist()=default;

    bool insert(const KeyType& key,const ValueType& value)
    {
        std::array<inner_node_ptr, CONST_MAX_LEVEL> arr;
        auto p = _head;
        for(int i = _level; i >= 0; i--)
        {
            while(p->forward[i] && p->forward[i]->key < key)
            {
                p = p->forward[i];
            }

            arr[i] = p;
        }

        p = p->forward[0];
        if(p && p->key == key)
        {
            return false;
        }

        int lev = random_level();
        if(lev > _level)
        {
            lev = ++_level;
            arr[lev] = _head;
        }

        auto ptr = std::make_shared<inner_node>(key, value, lev);
        for(int i = lev; i >= 0; i--)
        {
            p = arr[i];
            ptr->forward[i] = p->forward[i];
            p->forward[i] = ptr;
        }

        ++_size;
        return true;
    }

    std::shared_ptr<ValueType> erase(const KeyType& key)
    {
        std::array<inner_node_ptr, CONST_MAX_LEVEL> arr;
        auto p = _head;

        for(int i = _level; i >= 0; i--)
        {
            while(p->forward[i] && p->forward[i]->key < key)
            {
                p = p->forward[i];
            }

            arr[i] = p;
        }

        p = p->forward[0];
        if(p && p->key == key)
        {
            for(int i = 0; i <= _level; i++)
            {
                if(arr[i]->forward[i] != p)
                {
                    break;
                }

                arr[i]->forward[i] = p->forward[i];
            }

            if(_level > 0 && _head->forward[_level] == nullptr)
            {
                _level--;
            }

            _size--;

            return std::make_shared<ValueType>(p->value);
        }

        return nullptr;
    }

    std::shared_ptr<ValueType> find(const KeyType& k)
    {
        auto p = _head;
        for(int i = _level; i >= 0; i--)
        {
            while(p->forward[i] && p->forward[i]->key < k)
            {
                p = p->forward[i];
            }
        }

        p = p->forward[0];
        if(p && k == p->key)
        {
            return std::make_shared<ValueType>(p->value);
        }
        return nullptr;
    }

    int size() const
    {
        return _size;
    }

    int level() const
    {
        return _level + 1;
    }

    void visit(std::function<void(ValueType&)> fun)
    {
        inner_node_ptr p = _head;
        while(p->forward[0])
        {
            fun(p->forward[0]->value);
            p = p->forward[0];
        }
    }


private:
    int random_level()
    {
        int lev = 0;
        while(1)
        {
            if(_random()%2)
                lev++;
            else
                break;
        }

        return lev < CONST_MAX_LEVEL ? lev : CONST_MAX_LEVEL-1;
    }

    int _level;
    int _size;
    std::random_device _random;

    inner_node_ptr _head;
};


#endif // TG_SKIPLIST_H
 

测试代码

#include "tg_skiplist.h"
#include <iostream>

struct node
{
    node()=default;

    node(int k, double value):val(value + 0.5),key(k)
    {
    }

    double val;
    int key;
};

void print(node& n)
{
    std::cout<< n.key << "\t" << n.val <<std::endl;
}

int main()
{
    tg_skiplist<int,node> list;
    std::random_device random;

    random();

    for(int i = 0; i < 50; i++)
    {
        int k = random() % 50;
        auto tmp = std::make_shared<node>(k, k);
        list.insert(k, *tmp);
    }

    std::cout<<"#####################################"<<std::endl;
    list.visit(print);
    std::cout<< list.size() << "\t" << list.level() <<std::endl;
    std::cout<<"##################查找###################"<<std::endl;

    for(int i = 0; i < 10; i++)
    {
        auto ptr = list.find(i);
        if(ptr)
        {
            print(*ptr);
        }
        else
        {
            std::cout<< "找不到: key=" << i <<std::endl;
        }
    }
    std::cout<<"################删除#####################"<<std::endl;
    auto ptr = list.erase(5);
    if(ptr)
    {
        print(*ptr);
    }
    std::cout<<"##################查找###################"<<std::endl;
    for(int i = 0; i < 10; i++)
    {
        auto ptr = list.find(i);
        if(ptr)
        {
            print(*ptr);
        }
        else
        {
            std::cout<< "找不到: key=" << i <<std::endl;
        }
    }
}

测试结果

#####################################
0    0.5
2    2.5
3    3.5
4    4.5
5    5.5
6    6.5
9    9.5
10    10.5
11    11.5
12    12.5
13    13.5
14    14.5
15    15.5
16    16.5
17    17.5
18    18.5
19    19.5
20    20.5
23    23.5
26    26.5
28    28.5
29    29.5
30    30.5
31    31.5
33    33.5
34    34.5
35    35.5
38    38.5
40    40.5
41    41.5
42    42.5
43    43.5
46    46.5
48    48.5
49    49.5
35    6
##################查找###################
0    0.5
找不到: key=1
2    2.5
3    3.5
4    4.5
5    5.5
6    6.5
找不到: key=7
找不到: key=8
9    9.5
################删除#####################
5    5.5
##################查找###################
0    0.5
找不到: key=1
2    2.5
3    3.5
4    4.5
找不到: key=5
6    6.5
找不到: key=7
找不到: key=8
9    9.5
 

参考:https://blog.csdn.net/ict2014/article/details/17394259

猜你喜欢

转载自blog.csdn.net/f110300641/article/details/84068673
今日推荐