• skip-list(跳表)原理及C++代码实现


    跳表是一个很有意思的数据结构,它实现简单,但是性能又可以和平衡二叉搜索树差不多。

    据MIT公开课上教授的讲解,它的想法和纽约地铁有异曲同工之妙,简而言之就是不断地增加“快线”,从而降低时间复杂度。

    当“快线”的数量为lgn时,我们就得到了现在的快表——一个类似于平衡二叉搜索树的数据结构。

    网上没有比较标准的实现方案,CLRS中也没有给出伪代码。(可能是因为他们觉得太容易实现了...)所以我给出是一个完全由我自己根据快表性质写的一个版本,如果大家有更好的实现版本欢迎和我分享。

    增加层数的方案用的是抛硬币,即根据随机数来确定是否增加“快线”,这也是MIT公开课上给出的一个比较简单的实现方法。

    代码如下:(仅供参考)

      1 class Skiplist {
      2 private :
      3     struct Node {
      4         int key;
      5         Node * prev;
      6         Node * next;
      7         Node * down;
      8         Node * top;
      9         Node() : key(0), prev(nullptr), next(nullptr), down(nullptr), top(nullptr) {}
     10     };
     11 private :
     12     Node * head;
     13     int level;
     14     int size;
     15 private :
     16     void bindNewNode(Node * x, Node * p);
     17     void delNode(Node * x);
     18     Node * searchNode(int key);
     19 public :
     20     Skiplist() : head(new Node), level(1),size(0)
     21         {head->key = INT_MIN; srand(static_cast<int>(time(0)));}
     22     ~Skiplist() {delete head;}
     23     void insert(int key);
     24     void remove(int key);
     25     bool search(int key) {return (searchNode(key) != nullptr);}
     26     void showSkiplist();
     27     int getLevel() {return level;}
     28     int getSize() {return size;}
     29 };
     30 
     31 void Skiplist::bindNewNode(Node * x, Node * p) {
     32     if (!x->next) {
     33         x->next = p;
     34         p->prev = x;
     35     }
     36     else {
     37         p->next = x->next;
     38         x->next->prev = p;
     39         p->prev = x;
     40         x->next = p;
     41     }
     42 }
     43 
     44 void Skiplist::insert(int key) {
     45     Node * p = new Node;
     46     p->key = key;
     47 
     48     Node * x = head;
     49     while (1) { //find the prev node of p, which represents the right insert place
     50         if (x->key <= key) {
     51             if (x->next)
     52                 x = x->next;
     53             else if (x->down)
     54                 x = x->down;
     55             else break;
     56         }
     57         else if (x->prev->down)
     58             x = x->prev->down;
     59         else {
     60             x = x->prev;
     61             break;
     62         }
     63     }
     64     bindNewNode(x, p);
     65     while (rand() % 2) {  //throw the coin, then judge whether it needs to be higher according to the results
     66         Node * highp = new Node;
     67         highp->key = key;
     68         while (!x->top && x->prev)
     69             x = x->prev;
     70         if (x->top) {
     71             x = x->top;
     72             bindNewNode(x, highp);
     73             highp->down = p;
     74             p->top = highp;
     75         }
     76         else { //already the top, add a sentry
     77             Node * top = new Node;
     78             x = top;
     79             top->key = INT_MIN;
     80             top->down = head;
     81             head->top = top;
     82             head = top;
     83             bindNewNode(top, highp);
     84             highp->down = p;
     85             p->top = highp;
     86             ++level;
     87         }
     88         p = highp;
     89     }
     90     ++size;
     91 }
     92 
     93 void Skiplist::delNode(Node * x) {
     94     if (!x->next) { //node x is the last one
     95         if (x->prev == head && head->down) { //x is not at the bottom and x is the last one of this level
     96             head = head->down;
     97             head->top = nullptr;
     98             delete x->prev;
     99             --level;
    100         }
    101         else
    102             x->prev->next = nullptr;
    103     }
    104     else {
    105         x->prev->next = x->next;
    106         x->next->prev = x->prev;
    107     }
    108     delete x;
    109 }
    110 
    111 void Skiplist::remove(int key) {
    112     Node * x = searchNode(key);
    113     if (x) {
    114         while (x->down) {
    115             Node * y = x->down;
    116             delNode(x);
    117             x = y;
    118         }
    119         delNode(x);
    120         --size;
    121     }
    122 }
    123 
    124 Skiplist::Node * Skiplist::searchNode(int key) {
    125     Node * x = head;
    126     while (1) { //find the prev node of p, which represents the right insert place
    127         if (x->key == key)
    128             return x;
    129         else if (x->key < key) {
    130             if (x->next)
    131                 x = x->next;
    132             else if (x->down)
    133                 x = x->down;
    134             else
    135                 return nullptr;
    136         }
    137         else if (x->prev->down)
    138             x = x->prev->down;
    139         else {
    140             return nullptr;
    141         }
    142     }
    143 }
    144 
    145 void Skiplist::showSkiplist() {
    146     Node * x = head, * y = head;
    147     while (y) {
    148         x = y;
    149         while (x) {
    150             if (x->prev != nullptr)
    151                 cout << x->key << ' ';
    152             x = x->next;
    153         }
    154         cout << endl;
    155         y = y->down;
    156     }
    157 }
  • 相关阅读:
    MySQL5.7安装详细教程
    Java之GUI编程
    Java基础
    生成JavaDoc文档
    SpringtMVC运行流程:@RequestMapping 方法中的 Map、HttpServletRequest等参数信息是如何封装和传递的(源码理解)
    SpringCache @Cacheable 在同一个类中调用方法,导致缓存不生效的问题及解决办法
    Spring源码学习:第1步--在Spring源码中添加最简单的Demo代码
    Spring源码学习:第2步--使用SLF4j+Log4j日志框架替换掉其自身的commons-logging日志框架
    Spring源码学习:第0步--环境准备
    JasperReport报表
  • 原文地址:https://www.cnblogs.com/yxsrt/p/12249745.html
Copyright © 2020-2023  润新知