1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
/* SI 486H Spring 2016
   This is a skeleton for a skip list class that only supports
   insertion of height-1 nodes.
 
   Nodes are stored in "towers" which contain a list of forward-facing
   links ("flinks"), as well as a key and a value.
 
   To demo on a small random example, run "make skiplist && ./skiplist"
*/
 
#include <cstdlib>
#include <limits>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
 
using namespace std;
 
template <typename V>
class SkipList {
 protected:
  struct Tower {
    double key;
    V value;
    vector<Tower*> flinks;
 
    Tower(int h, double key, V value) {
      this->key = key;
      this->value = value;
      this->flinks.insert(this->flinks.begin(), h+1, static_cast<Tower*>(NULL));
    }
  };
 
  Tower* start;
  Tower* end;
  int thesize;
 
 public:
  SkipList() {
    this->start = new Tower(0, -numeric_limits<double>::infinity(), V());
    this->end = new Tower(0, numeric_limits<double>::infinity(), V());
    this->start->flinks[0] = this->end;
    this->thesize = 0;
  }
 
  int height() {
    return this->start->flinks.size()- 1;
  }
 
  int size() {
    return this->thesize;
  }
 
  void insert(double key, V value) {
    int h = 1; // TODO: choose height randomly!
    Tower* newTower = new Tower(h, key, value);
 
    // Grow height of start/end as needed
    while (h >= height()) {
      this->start->flinks.push_back(this->end);
      this->end->flinks.push_back(NULL);
    }
 
    Tower* currentTower = this->start;
    int level = currentTower->flinks.size()-1;
    while (level >= 0) {
      if (key > currentTower->flinks[level]->key) {
        // Move right if we can on this level
        currentTower = currentTower->flinks[level];
      } 
      else {
        // Otherwise go down a level
        if (level <= h) {
          // Insert the new tower on this level
          newTower->flinks[level] = currentTower->flinks[level];
          currentTower->flinks[level] = newTower;
        }
        level -= 1;
      }
    }
 
    this->thesize += 1;
  }
 
  void print(ostream& out = cout) {
    /* Prints a nice pretty representation of the skip list */
    for (int level = height(); level >= 0; --level) {
      Tower* currentTower = this->start;
      while (currentTower != this->end) {
        stringstream ss;
        ss << "(" << currentTower->key << ")";
        if (level >= currentTower->flinks.size()) {
          for (int i=0; i < ss.str().length(); ++i) out << "-";
        }
        else { out << ss.str(); }
        out << "--";
        currentTower = currentTower->flinks[0];
      }
      out << "(" << currentTower->key << ")\n";
    }
  }
 
};
 
int main() {
  unsigned long rseed;
  ifstream rin("/dev/urandom");
  rin.read((char*)&rseed, sizeof(rseed));
  rin.close();
  srand(rseed);
 
  // Randomly insert 10 numbers and print the resulting skip list
  SkipList<string> S;
  for (int i=0; i<10; ++i) {
    S.insert(rand() % 64, "this is the value");
  }
  S.print();
 
  return 0;
}