AlgoPlus v0.1.0
Loading...
Searching...
No Matches
skip_list.h
1#ifndef SKIP_LIST_H
2#define SKIP_LIST_H
3
4#ifdef LINKED_LIST_VISUALIZATION_H
5#include "../../visualization/list_visual/linked_list_visualization.h"
6#endif
7
8#ifdef __cplusplus
9#include <iostream>
10#include <memory>
11#include <stdexcept>
12#include <vector>
13#include <unordered_set>
14#endif
15
20template <typename T> class skip_list {
21 public:
28 explicit skip_list(int MAX_LEVEL, float PROB) {
29 try {
30 if (MAX_LEVEL < 5) {
31 MAX_LEVEL = MAX_LEVEL;
32 root = std::make_shared<node>(0, MAX_LEVEL);
33 } else {
34 throw std::invalid_argument("Max level value is too high");
35 }
36 if (PROB > 0.0 && PROB < 1.0) {
37 PROB = PROB;
38 } else if (PROB >= 1.0) {
39 throw std::invalid_argument(
40 "Probability value is greater or equal to 1");
41 } else if (PROB <= 0.0) {
42 throw std::invalid_argument(
43 "Probability value is smaller or equal to 0");
44 }
45 } catch (std::invalid_argument &e) {
46 std::cerr << e.what() << '\n';
47 return;
48 }
49 }
50
56 skip_list(const skip_list &s) : level(s.level), PROB(s.PROB), MAX_LEVEL(s.MAX_LEVEL), root(s.root) {
57
58
59
60
61 }
62
69 level = s.level;
70 PROB = s.PROB;
71 MAX_LEVEL = s.MAX_LEVEL;
72 root = s.root;
73 return *this;
74 }
75
79 ~skip_list() noexcept {}
80
85 void insert(T key) {
86 std::shared_ptr<node> head = root;
87 std::vector<std::shared_ptr<node>> update(MAX_LEVEL + 1, nullptr);
88
89 for (int i = level; i >= 0; i--) {
90 while (head->next[i] != nullptr && head->next[i]->key < key) {
91 head = head->next[i];
92 }
93 update[i] = head;
94 }
95
96 head = head->next[0];
97 if (!head || head->key != key) {
98 int lvl = rand_lvl();
99 if (lvl > level) {
100 for (int i = level + 1; i < lvl + 1; i++) {
101 update[i] = root;
102 }
103 level = lvl;
104 }
105
106 std::shared_ptr<node> nn = std::make_shared<node>(key, lvl);
107 for (int i = 0; i <= lvl; i++) {
108 nn->next[i] = update[i]->next[i];
109 update[i]->next[i] = nn;
110 }
111 }
112 }
113
114 class Iterator;
115
121 Iterator begin() { return Iterator(root->next[0]); }
122
128 Iterator end() { return Iterator(nullptr); }
129
134 void remove(T key) {
135 std::shared_ptr<node> x = root;
136 std::vector<std::shared_ptr<node>> update(MAX_LEVEL + 1, nullptr);
137
138 for (int64_t i = level; i >= 0; i--) {
139 while (x->next[i] && x->next[i]->key < key) {
140 x = x->next[i];
141 }
142 update[i] = x;
143 }
144
145 x = x->next[0];
146 if (x && x->key == key) {
147 for (int64_t i = 0; i <= level; i++) {
148 if (update[i]->next[i] != x) {
149 break;
150 }
151 update[i]->next[i] = x->next[i];
152 }
153 while (level > 0 && root->next[level] == nullptr) {
154 level--;
155 }
156 }
157 }
158
164 bool search(T key) {
165 std::shared_ptr<node> x = root;
166 for (int64_t i = level; i >= 0; i--) {
167 while (x->next[i] && x->next[i]->key < key) {
168 x = x->next[i];
169 }
170 }
171 x = x->next[0];
172 if (x && x->key == key) {
173 return true;
174 }
175 return false;
176 }
177
183 #ifdef LINKED_LIST_VISUALIZATION_H
184 void visualize(){
185 std::string generated = this->generate();
186 linked_list_visualization::visualize(generated);
187 }
188 #endif
189
193 friend std::ostream &operator<<(std::ostream &out, skip_list<T> &l) {
194 std::shared_ptr<node> root = l.root;
195 out << "{";
196 for (int i = 0; i <= l.level; i++) {
197 out << i << ": ";
198 std::shared_ptr<node> curr = l.root->next[i];
199 while (curr != nullptr) {
200 out << curr->key << " ";
201 curr = curr->next[i];
202 }
203 out << '\n';
204 }
205 out << "}" << '\n';
206 return out;
207 }
208
209 private:
210 int MAX_LEVEL{};
211 float PROB{};
212
218 struct node {
219 T key;
220 std::vector<std::shared_ptr<node>> next;
221 node(T key, int level, void *value = nullptr) : key(key) {
222 for (int i = 0; i < level + 1; i++) {
223 next.push_back(nullptr);
224 }
225 }
226 };
227
228 int rand_lvl() {
229 float r = (float)rand() / RAND_MAX;
230 int lvl = 0;
231 while (r < PROB && lvl < MAX_LEVEL) {
232 lvl++;
233 r = (float)rand() / RAND_MAX;
234 }
235 return lvl;
236 }
237
238 int level{0};
239 std::shared_ptr<node> root;
240
241 std:: string generate_node(std::string node_val, int levs){
242 std::string gen;
243 gen += node_val;
244 gen += " [label=\"<";
245 gen += std::to_string(levs);
246 gen += "> ";
247 gen += node_val;
248 for(int i=levs-1;i>=0;i--){
249 gen += " | <";
250 gen += std::to_string(i);
251 gen += "> ";
252 gen += node_val;
253 }
254 gen += "\"];";
255 gen += '\n';
256 return gen;
257 }
258
259 std::string generate_edge(std::string prev_val, std::string curr_val, int lev){
260 std::string gen;
261 gen += prev_val;
262 gen += ':';
263 gen += std::to_string(lev);
264 gen += " -> ";
265 gen += curr_val;
266 gen += ':';
267 gen += std::to_string(lev);
268 gen += " ;\n";
269 return gen;
270 }
271
272 std::string generate() {
273 std::string gen;
274 gen += "rankdir=LR;";
275 gen += '\n';
276 gen += "node [shape=record;]";
277 gen += '\n';
278 std::unordered_set<std::string> S;
279 int m_level = std::min(level, (int)root->next.size()); // See if this is a parameter
280 gen += generate_node("root", m_level+1);
281 gen += generate_node("NULL", m_level+1);
282 gen += generate_edge("root", "NULL", m_level+1);
283 for(int i=m_level;i>=0;i--){
284 std::shared_ptr<node> head = root;
285 head = head->next[i];
286 std::string prev_val = "root";
287 std::string head_key;
288 while(head){
289 if(std::is_same_v<T, std::string>){
290 head_key = head->key;
291 } else {
292 head_key = to_string(head->key);
293 }
294 if(S.find(head_key) == S.end()){
295 S.insert(head_key);
296 gen += generate_node(head_key, i);
297 }
298 gen += generate_edge(prev_val, head_key, i);
299 prev_val = head_key;
300 head = head->next[i];
301 }
302 gen += generate_edge(prev_val, "NULL", i);
303 }
304 return gen;
305 }
306};
307
311template <typename T> class skip_list<T>::Iterator {
312 private:
313 std::shared_ptr<node> ptr;
314
315 public:
320 explicit Iterator(std::shared_ptr<node> ptr) noexcept : ptr(ptr) {}
321
328 Iterator &operator=(std::shared_ptr<node> current) {
329 this->ptr = current;
330 return *(this);
331 }
332
339 if (ptr != nullptr) {
340 ptr = ptr->next[0];
341 }
342 return *(this);
343 }
344
351 Iterator it = *this;
352 ++*(this);
353 return it;
354 }
355
362 bool operator!=(const Iterator &it) { return ptr != it.ptr; }
363
369 T operator*() { return ptr->key; }
370};
371
372#endif
Iterator class.
Definition skip_list.h:311
Iterator operator++(int)
operator ++ for type Iterator
Definition skip_list.h:350
T operator*()
operator * for type Iterator
Definition skip_list.h:369
bool operator!=(const Iterator &it)
operator != for type Iterator
Definition skip_list.h:362
Iterator & operator=(std::shared_ptr< node > current)
= operator for Iterator type*
Definition skip_list.h:328
Iterator & operator++()
operator ++
Definition skip_list.h:338
Iterator(std::shared_ptr< node > ptr) noexcept
Construct a new Iterator object.
Definition skip_list.h:320
skip_list class.
Definition skip_list.h:20
skip_list(int MAX_LEVEL, float PROB)
skip_list constructor.
Definition skip_list.h:28
Iterator end()
pointer that points to the last element of the list
Definition skip_list.h:128
void remove(T key)
remove function.
Definition skip_list.h:134
~skip_list() noexcept
Destroy the skip list object.
Definition skip_list.h:79
skip_list & operator=(const skip_list &s)
operator = for the skip_list class
Definition skip_list.h:68
skip_list(const skip_list &s)
Copy constructor for the skip_list class.
Definition skip_list.h:56
friend std::ostream & operator<<(std::ostream &out, skip_list< T > &l)
visualize function returns a .dot file that can be previewd with graphviz plugin in vscode
Definition skip_list.h:193
Iterator begin()
pointer that points to the first element of the list
Definition skip_list.h:121
void insert(T key)
insert function.
Definition skip_list.h:85
bool search(T key)
search function.
Definition skip_list.h:164
@ key
the parser read a key of a value in an object