【数据结构】跳跃链表(Skip list)

来源:互联网 发布:股票数据接口插件 编辑:程序博客网 时间:2024/05/16 11:12

普通的链表存在一个严重的缺陷:

需要顺序扫描才能找到所需要的元素。而且查找从链表的开头开始,只有找到了所需要的元素,或者直到链表的末尾都没有找到这个元素时才会停下来。将量表进行排序可以加速查找的过程,但是仍然需要顺序查找。因此,很容易想到,链表最好可以跳过某些节点,以避免顺序处理。

从而,引出了跳跃链表,跳跃链表是有序链表的一个有趣的变种,可以进行非顺序查找。

在有n个节点的跳跃链表中,对于每个满足1≦k≦└ lgn ┘ 和 1≦└ n/2^(k-1)┘-1 的k和i,位于2^(k-1)·i的结点指向位于2^(k-1)·(i+1)的节点。这意味着第二个节点指向前面距离两个单位的节点,第四个节点指向前面距离4个单位的节点,以此类推。所以,要在链表的结点中包含不同树木的指针:半数节点只有一个指针,1/4的节点有两个指针,1/8节点有3个指针,一次列退。可以看出,指针数表明了每个节点的级,而级的数量为maxLevel = └ lg n ┘+1

为了查找元素e1,应该从最高层上的指针开始,找到该元素就成功地结束查找。如果到达该链表的末尾,或者遇到大雨元素e1的某个元素key,就包含key的那个节点的前一个节点重新开始查找,但是这次查找是从比前面低一级的指针开始。知道找到e1,或者沿着第一级的指针到达了链表的末尾,或者找到一个大于e1的元素,查找才会停止。下面给出为代码:

search(元素e1)p = 最高层i上的非空链表;while 没有找到 e1 且 i ≥ 0if p-> key < e1p = 从 --i级上p的前驱开始的子链表;else if p->key > e1if p是i级上的最后一个节点p = 在 <i的最高级上从p开始的非空子链表i = 新的级数else p = p-> next

下面是跳表的具体实现:

//// Created by 大幕 on 2017/9/13.//#ifndef SKIPLIST_SKIPLIST_H#define SKIPLIST_SKIPLIST_H#include <iostream>const int DefaultSize = 100;template <typename E,typename K>struct SkipNode{    E data;         //数据域    SkipNode<E,K> **link;   //指针数组域    SkipNode(int size = DefaultSize){   //构造函数        link = new SkipNode<E,K> *[size];        if(link = nullptr)        {            std::cerr <<"存储分配失败!"<<std::endl;            exit(1);        }    }    ~SkipNode()    {        delete []link;    }};/** * 跳表类定义 * 其中large是一个比字典中任何一个元素的值都大的值 * 放在尾结点中。0级链上的元素值从左向右按照升序进行排列 * 但是不包括附加头结点 */template <typename E,typename K>class SkipList{public:    SkipList(K large,int maxLev = DefaultSize); //构造函数    ~SkipList();    bool Search(const K k1,E& e1)const;     //搜索函数    E& getData(SkipNode<E,K> *current)    {        if(current != nullptr)            return current->data;        else            return nullptr;    }    bool Insert(const K k1,E &e1);      //插入函数    bool Remove(const K k1,E &e1);      //删除函数private:    int maxLevel;       //所允许的最大级数    int Levels;    K TailKey;    SkipNode<E,K> *head;    //附加头结点    SkipNode<E,K> *tail;    //附加尾结点    SkipNode<E,K> **last;   //指针数组    int level();    SkipNode<E,K> *SaveSearch(const K k1);};/***跳表的构造函数初始化Level(当前出现的最大级别)、maxLevel、TailKey(所有元素值均小于这个值) * 还为附加头结点和尾结点分配空间。在插入和删除之前进行搜索时, * 所遇到的每条链上的最后一个元素均被放在数组last中。附加头结点中有maxLevel+1个用于指向 * 各级链的指针被初始化为指向尾结点(空链表). * 析构函数释放链表中用到的所有空间 *//** * 跳表的构造函数和析构函数 */template <typename E,typename K>SkipList<E,K>::SkipList(K large, int maxLev) {    //构造函数,建立空的多级链    maxLevel = maxLev;          //最大级链数目    TailKey = large;            //控制扫描的最大关键码    Levels = 0;    head = new SkipNode<E,K>(maxLevel+1);   //附加头结点,有maxLevel+1个指针    tail = new SkipNode<E,K>(0);            //附加尾结点,有0个指针    last = new SkipNode<E,K> *[maxLevel+!]; //跳表的多级链的头指针    tail -> data = large;    for(int i =0;i<maxLevel;i++)    {        head->link[i] = tail;    }}template<typename E,typename K>SkipList<E,K>::~SkipList() {    /**     * 析构函数,释放链表上的所有元素节点     */    SkipNode<E,K> *next;    while(head != tail)    {        next = head->link[0];        delete head;        head = next;    }    delete tail;    delete []last;}/** * 跳表的搜索。插入和删除 *//** * 1.跳表的搜索: * 跳表有两个搜索函数,当需要搜索一个值为k1的元素时,可用公共成员函数Search * 如果找到想要搜索的元素,则将这个元素返回到e1中,并返回true,否则返回false. * Search从最飞机链(Level级,仅含有一个元素)的表头开始搜索,顺着指针向右搜索 * 逐步逼近要搜索的元素,一直走到0级链。 * 当从for循环退出时,正好处于要寻找的元素的左边。与0级链的下一个元素进行比较, * 就能知道要找的元素是否在跳表中 * * 第二个搜索函数是私有函数SaveSearch(),作用是由插入和删除进行调用, * SaveSearch不仅仅包含了Search的全部功能,而且可以把每一级中遇到的最后一个结点存放到数组last中FFFFFF */template <typename E,typename K>bool SkipList<E,K>::Search(const K k1, E &e1) const {    if(k1 > TailKey)        return false;    SkipNode<E,K> *p = head;    for(int i = Levels;i >= 0;i--)      //逐级向下搜索    {        while(p->link[i]->data < k1)    //重载,元素关键码判小于            p = p->link[i];    }    e1 = p->link[0]->data;    return e1 == k1;     //重载,元素关键码判等于}template <typename E,typename K>SkipNode<E,K>* SkipList<E,K>::SaveSearch(const K k1) {    if(k1 > TailKey)        return nullptr;    SkipNode<E,K> *p = head;    for(int i = Levels; i >= 0; i--) {        while (p->link[i]->data < k1)            p = p->link[i];        last[i] = p;        //记下最后比较的及诶单    }    return p->link[0];}#endif //SKIPLIST_SKIPLIST_H

原创粉丝点击