跳表分析与实现

来源:互联网 发布:怎么查看端口是否打开 编辑:程序博客网 时间:2024/05/22 06:15

一、什么是跳表
跳表全称叫做跳跃表,简称跳表。跳表是一个随机化的数据结构,可以被看做二叉树的一个变种,它在性能上和红黑树,AVL树不相上下,但是跳表的原理非常简单,目前在Redis和LeveIDB中都有用到。
在对有序顺序表进行搜索时,使用二分查找时间复杂度是O(logn),但是有序顺序表的插入和删除却是O(n)的算法。
在对有序链表进行搜索时,时间复杂度是O(n),但是对链表的插入算法却是O(1)。
可以看到有序顺序表和链表各有各的优势,同时也有自身的缺点,而我们要讲的跳跃表就是集成了以上两种数据结构的优点,但是自身多耗费一部分空间的数据结构。

二、跳表的原理
跳表的原理非常简单,跳表其实就是一种可以进行二分查找的有序链表。跳表的数据结构模型如图:
这里写图片描述

可以看到,跳表在原有的有序链表上面增加了多级索引,通过索引来实现快速查找。首先在最高级索引上查找最后一个小于当前查找元素的位置,然后再跳到次高级索引继续查找,直到跳到最底层为止,这时候以及十分接近要查找的元素的位置了(如果查找元素存在的话)。由于根据索引可以一次跳过多个元素,所以跳查找的查找速度也就变快了。
最理想的情况下,跳表就像一颗满二叉树,查找的时间复杂度是O(logn)。问题 是怎么决定一个结点有多少级索引???
针对这个问题跳表的创始人提出了一种抛硬币的方法,用随机函数产生一个0或者1,如果是1的话则leve++,直到产生0位置,当数据量足够大的时候,leve的取值会趋向于正态分布。

三、跳表与红黑树,AVL树等平衡数据结构的比较
跳表与红黑树和AVL树相比,效率不相上下,但是它胜在实现起来比较简单,我们可以很快的实现出来。跳表在更新的时候需要改动的地方很少,而红黑树和AVL树需要改动的地方很多。如果在多线程的情况下,红黑树和AVL树在维持平衡的时候,需要的锁资源很多,越是在靠近根节点的地方越容易产生竞争。但是跳表的操作更加局部性一点,需要锁住的资源很少。

四、跳表的实现
跳表的性质:
1、由很多层组成
2、每一层都是一个有序链表
3、最底层的链表包含所有元素
4、如果一个元素出现在第i层的链表中,则它在i-1层中也会出现。
5、上层节点可以跳转到下层。
跳表的实现:

#ifndef _SKIPLIST_H__#define _SKIPLIST_H__#include<time.h>#include<iostream>#include<vector>#include<cstdio>#include<cstdlib>using namespace std;#define MAXLEVE 8                                             //跳表的最大层数template<typename K,typename V>struct SkipNode                                               //跳表的节点类型{   K _key;               V _value;     size_t _sz;                                                //表示该节点的层数   vector<SkipNode<K,V> *> _pleve;                            //存放每一层的指针   SkipNode(K key=K(),V value=V(),size_t sz=size_t())               :_key(key)        ,_value(value)        ,_sz(sz)    {        _pleve.resize(0);        for(size_t i=0;i<sz;i++)        {            _pleve.push_back(NULL);        }    }   ~SkipNode()   {        _key=-1;        _value=-1;        _sz=-1;        _pleve.clear();   }};template<typename K,typename V>class SkipList                                               //跳表类{public:    typedef SkipNode<K,V> Node;    SkipList();    void Insert(K key,V value);    bool Find(K key,V& value);    bool Erase(K key);    void Print();    int GetLeve();                                            //返回跳表的最大层数    size_t Size();    ~SkipList();private:    int Random();                                             //产生随机层数的函数protected:                                          SkipList(SkipList<K,V> &);                                //防拷贝    SkipList<K,V>& operator=(SkipList<K,V>);                  //防赋值private:    Node *_head;    int _maxLeve;                                             //记录跳表的最大层数    int _size;                                                //记录跳表最底层元素的个数};#endif    //_SKIPLIST_H__template<typename K,typename V>size_t SkipList<K,V>::Size(){    return _size;}template<typename K,typename V>int SkipList<K,V>::GetLeve(){    return _maxLeve;}template<class K,class V>int SkipList<K,V>::Random(){    int leve=1;    while(rand()%2&&leve<=MAXLEVE)                 //产生0或1,1的话leve++,最后平均下来leve的值趋向与正态分布    {        leve++;    }    return leve;}template<typename K,typename V>SkipList<K,V>::SkipList(){    _maxLeve=1;    _size=0;    _head=new Node(-1,-1,MAXLEVE);}template<typename K,typename V>void SkipList<K,V>::Insert(K key,V value){    int i=_maxLeve-1;    int j=0;    Node* cur=_head;                                     //指向跳表的起点    Node* s[MAXLEVE];                                     //用来保存每层向下跳转位置的前驱    while(i>=0)    {        while(cur->_pleve[i])        {            if(key>=cur->_pleve[i]->_key)            {                cur=cur->_pleve[i];            }            else                break;        }        s[j++]=cur;        i--;    }    i=0;                                                int leve=Random();                                    //产生一个随机层数    _maxLeve<leve?_maxLeve=leve:_maxLeve;                 //更新跳表的最大层数    Node* newNode=new Node(key,value,leve);                  //创建一个节点    for(i=0;i<leve;i++)    {        if(i<j)           {            newNode->_pleve[i]=s[j-i-1]->_pleve[i];            s[j-i-1]->_pleve[i]=newNode;        }        else        {            _head->_pleve[i]=newNode;        }    }    _size++;}template<typename K,typename V>bool SkipList<K,V>::Find(K key,V& value){    int i=_maxLeve-1;    Node* cur=_head;                                     //指向跳表的起点    while(i>=0)    {        while(cur->_pleve[i])        {            if(key>=cur->_pleve[i]->_key)            {                cur=cur->_pleve[i];            }            else                break;        }        i--;    }    i=0;    if(cur->_key==key)                                      //最好采用仿函数进行比较    {        value=cur->_value;        return true;    }    return false;}template<typename K,typename V>bool SkipList<K,V>::Erase(K key){    int i=_maxLeve-1;    int j=0;    Node* cur=_head;                                     //指向跳表的起点    Node* s[MAXLEVE];                                     //用来保存每层向下跳转位置的前驱    while(i>=0)    {        while(cur->_pleve[i])        {            if(key>cur->_pleve[i]->_key)            {                cur=cur->_pleve[i];            }            else                break;        }        s[j++]=cur;        i--;    }    if(cur->_pleve[0]&&cur->_pleve[0]->_key==key)    {        cur=cur->_pleve[0];        int leve=cur->_sz;        Node *del=NULL;        del=cur;        for(i=0;i<leve;i++)                                //将该节点的每层都进行删除        {            s[j-i-1]->_pleve[i]=cur->_pleve[i];        }        delete del;        while(_maxLeve>1)                                    //如果某一层只有头结点,则删除整层        {            if(NULL==_head->_pleve[_maxLeve-1])                _maxLeve--;            else                break;        }        if(_size>0)            _size--;    }    return false;}template<typename K,typename V>void SkipList<K,V>::Print(){    int i=_maxLeve-1;    while(i>=0)    {        Node* cur=_head;        printf("this is %d leve:",i+1);        while(cur)        {            cout<<cur->_key<<":"<<"["<<cur->_value<<"]"<<" ";            cur=cur->_pleve[i];        }        i--;        printf("\n");    }}template<typename K,typename V>SkipList<K,V>::~SkipList(){    Node* cur=_head;    Node* del;    while(cur)    {        del=cur;        cur=cur->_pleve[0];        delete del;    }    _head=NULL;}例:#include"skiplist.hpp"void test(){    {        SkipList<int,int> s;    //    s.Insert(1,1);    //    s.Insert(3,3);    //    s.Insert(2,2);    //    s.Insert(4,4);    //    s.Insert(5,5);    //    s.Insert(6,6);    //    s.Insert(7,7);    //    s.Insert(8,8);    //    s.Insert(9,9);    //    s.Insert(10,10);        s.Erase(6);    //    s.Insert(11,11);    //    s.Insert(12,12);        s.Print();        cout<<s.GetLeve()<<endl;;        cout<<s.Size()<<endl;;    }    cout<<"destroy SkipList"<<endl;;//    s.Erase(1);//    s.Print();//    s.Erase(2);//    s.Print();//    s.Erase(3);//    s.Print();//    int i=1;//    for(i=1;i<13;i++)//    {//        printf("delete %d leve\n",i-1);//        s.Erase(i);//        s.Print();//    }//    cout<<endl;//    s.Print();//    int value=0;//    int key=13;//    if(s.Find(key,value))//    {//        cout<<"key="<<key<<",value is:"<<value<<endl;//    }//    else//    {//        cout<<"not found"<<endl;//    }}int main(){    test();    return 0;}
原创粉丝点击