跳表(skip list)的c++实现

跳表(skip list)的c++实现首先声明 是转摘别人的代码 本人稍作更改 在 microsoftvis 环境下测试通过 要理解跳表是如何实现的 看懂这个图很重要 摘自维基百科 nbsp Aschematicpi Eachboxwitha

首先声明,是转摘别人的代码,本人稍作更改。在microsoft visual studio comunity 2017环境下测试通过。要理解跳表是如何实现的,看懂这个图很重要(摘自维基百科)

 

跳表数据结构

A schematic picture of the skip list data structure. Each box with an arrow represents a pointer and a row is a linked list giving a sparse subsequence; the numbered boxes (in yellow) at the bottom represent the ordered data sequence. Searching proceeds downwards from the sparsest subsequence at the top until consecutive elements bracketing the search element are found

我翻译一下:跳表数据结构的示意图。每个带箭头的箱子代表一个指针,每一行是是一个链表,每个链表给出一个稀疏子序列;底部的编号的箱子(黄色)表示有序的数据列。搜索过程由顶部的最稀疏的子序列开始,方向朝下,直到包围搜索元素的两个连续元素被发现。

由此可见:元素类型包含一个数据值(黄色箱子)和一个指针向量(用next表示),指针指向某个元素。因为向量的成员也叫元素,为了区别,下面我把链表的元素简称为元素,把指针向量的元素称为指针。所有元素的指针是紧密排列的,这表明指针的个数(next.size())就是该元素出现在子序列中的次数。每个指针都水平向右指向,这表明子序列由相同下标的指针指向的元素组成,并且指针的下标编号和子序列的编号(从0开始编号,0号表示最底层,这一层包含所有元素)是相同的,因此我们可以很方便的通过指针向量的下标操作来访问每一层子序列的元素。每个元素的指针个数由随机数产生,最大max_height,拥有最大指针个数的元素决定了链表的高度。从图形我们也可以很直观的看出每一层子序列是一个单向有序链表,而且越高的子序列越稀疏。

搜索过程结束的条件是:直到p和p->next[0](p->key< x <=p->next[0]->key)这两个元素被发现。p表示搜索经历的元素,x表示搜索元素值,next[0]表示最底层子序列上p指向的下一个元素,如果x==p-next[0]->key,则p->next[0]就是要找的元素,否则数据列不存在x。

看懂了这个图,基本上就能理解如何用c++来实现跳表了。

// exercise18.11.cpp: 定义控制台应用程序的入口点。 // #include "stdafx.h" // Chapter 18 exercise 11: implement a skip list. Following Ottmann & Widmayer, // "Algorithmen and Datenstrukturen" (3rd Edition), 1997, Chapter 1.7.1 #include "d:/download/stroustrup-ppp-master/lib_files/std_lib_facilities.h" struct element { element(int k, int height) : key(k), next(height) { } //height:元素的层高 int key; vector 
  
    next; }; class skip_list { public: skip_list(); element* find(int x); void insert(int x); void remove(int x); void print(); void debug_print(); void desc_print(); int get_height() { return height; } private: const int max_height = 4; const int infty = numeric_limits 
   
     ::max(); element head; element tail; int height; //有效层高,从0开始编号,所以实际有效层高数是height+1,可能的最大值是max_height-1 int random_height(); }; // initialise empty list with head element's next pointing to tail element // on all list levels skip_list::skip_list() :head(0, max_height), tail(infty, 1), height(0) { for (int i = 0; i 
    
      = 0; --i) { while (p->next[i]->key < x) { p = p->next[i]; } } // now either p == &head and x <= p->next[0]->key // or p != &head and p->key < x <= p->next[0]->key p = p->next[0]; if (p->key == x) return p; // x is at position p in list else return 0; // x is not in list } // inserts element with key x into list void skip_list::insert(int x) { vector 
     
       update(max_height); element* p = &head; for (int i = height; i >= 0; --i) { while (p->next[i]->key < x) { p = p->next[i]; } update[i] = p; } p = p->next[0]; if (p->key == x) return; // key x exists already in list int new_height = random_height(); if (new_height > height) { // link new element to head, adjust list height for (int i = height + 1; i <= new_height; ++i) { update[i] = &head; } height = new_height; } // create new element with height new_height and key x p = new element(x, new_height+1); // insert p into level i lists immediately after element update[i] for (int i = 0; i <= new_height; ++i) { p->next[i] = update[i]->next[i]; update[i]->next[i] = p; } } // removes element with key x from list void skip_list::remove(int x) { vector 
      
        update(max_height); element* p = &head; for (int i = height; i >= 0; --i) { while (p->next[i]->key < x) p = p->next[i]; update[i] = p; } p = p->next[0]; // if found, remove and potentially reduce list height if (p->key == x) { for (int i = 0; i 
                next.size(); ++i) { // remove p from level i list update[i]->next[i] = p->next[i]; } while (height >= 1 && head.next[height]->key == infty) --height; delete p; } } void skip_list::print() { element* p = head.next[0]; cout << "{"; while (p->key != infty) { cout << ' ' << setw(2) << p->key; p = p->next[0]; } cout << " }" << "\n"; } // print lists at higher levels void skip_list::debug_print() { for (int i = 0; i <= height; ++i) { element* p = head.next[0]; cout << "Lvl " << i+1 << ": {"; while (p->key != infty) { if (p->next.size() > i) cout << ' ' << setw(2) << p->key; else cout << " "; p = p->next[0]; } cout << " }" << "\n"; } } void skip_list::desc_print() { for (int i = height; i >= 0; --i) { element* p = head.next[0]; //最底层才包含所有元素 cout << "Lvl " << i+1 << ": {"; while (p->key != infty) { if (p->next.size() > i) cout << ' ' << setw(2) << p->key; else cout << " "; p = p->next[0]; } cout << " }" << "\n"; } } int skip_list::random_height() { int rand_height = 0; while (randint(10000)<5000 && rand_height                   > x; if (x == -1) return 0; element* p = sl.find(x); sl.remove(x); sl.desc_print(); cout << "\n"; } } catch (exception& e) { cerr << "exception: " << e.what() << endl; } catch (...) { cerr << "exception\n"; }                                          

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/176617.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月26日 下午9:29
下一篇 2026年3月26日 下午9:29


相关推荐

  • bigdecimal 乘法_BigDecimal的浮点数运算能保证精度的原理是什么?

    bigdecimal 乘法_BigDecimal的浮点数运算能保证精度的原理是什么?不是所有的十进制数都能转化为有限位二进制数的 1 任意十进制整数可以转化为有限位数的二进制整数 如 123 64 32 16 8 2 1 转化为二进制整数是 2 能分解为以 1 2 n 为单位的十进制小数 可以转化为有限位数的二进制小数 如十进制数 13 16 0 8125 它可以是拆成 13 16 1 2 1 4 1 16 或者直接可以看作是 13 个 1 16 所组成 而 1 2 1 4 1

    2026年3月18日
    2
  • html中超链接打电话怎么写,html超链接代码书写格式

    html中超链接打电话怎么写,html超链接代码书写格式几乎我们所有浏览的网页 或多或少都存在一些超链接 点击超链接就可以从一个页面跳转到另一个页面 超链接使得网络中 无数的网页能够彼此相互连接 方便网页浏览者进入到另一个相关的页面 html 超链接作用 HTML 超链接可以是任意某个字 词 或者某一个词组 也可以是一句话 一段文字 任意图片也可以成为超链接 你可以点击这些带有超链接功能的元素内容 就可以跳转到超链接指向的目标地址 这个目标地址可以是一个任意

    2026年1月17日
    2
  • 概念结构设计[通俗易懂]

    概念结构设计[通俗易懂]

    2022年8月3日
    7
  • android studio java和xml_android studio闪退

    android studio java和xml_android studio闪退Program:         $JDKPath$\bin\javah.exeParameters:      -classpath$OutputPath$;$ModuleSdkPath$/platforms/android-25/android.jar-jni-d$ModuleFileDir$/src/main/jni$FileClass$

    2026年3月4日
    5
  • 气动康复手套设计

    气动康复手套设计

    2026年3月15日
    2
  • 深信服scsa知识点一「建议收藏」

    深信服scsa知识点一「建议收藏」1.AH51端口ESP50端口2.IPSEC能加密经过NAT转换的报文,但是不能验证经过NAT转换的报文,在穿越NAT时IKE协商的IP地址和端口不匹配3.非对称加密,使用其中一个密钥加密后只能使用另一个密钥解密4.加密和解密是对数据进行的某种交换,加密和解密的过程都在密钥的控制下完成的5.SANGFORVPN建立总部与分支的VPN类型,需要使用虚拟IP6.标准IPSEC中,启用DPD(对等体死亡检测)可以防止VPN隧道黑洞7.对于IPv4,IPSEC是可选的,对于IPv6,IPSEC是强

    2022年6月20日
    43

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号