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 <string>
13#include <unordered_set>
14#include <vector>
15#endif
16
20
21template <typename T> class skip_list {
22 public:
29 inline explicit skip_list(int MAX_LEVEL, float PROB) {
30 try {
31 if (MAX_LEVEL < 5) {
32 MAX_LEVEL = MAX_LEVEL;
33 root = std::make_shared<node>(0, MAX_LEVEL);
34 } else {
35 throw std::invalid_argument("Max level value is too high");
36 }
37 if (PROB > 0.0 && PROB < 1.0) {
38 PROB = PROB;
39 } else if (PROB >= 1.0) {
40 throw std::invalid_argument("Probability value is greater or equal to 1");
41 } else if (PROB <= 0.0) {
42 throw std::invalid_argument("Probability value is smaller or equal to 0");
43 }
44 } catch (std::invalid_argument& e) {
45 std::cerr << e.what() << '\n';
46 return;
47 }
48 }
49
55 inline skip_list(const skip_list& s)
56 : level(s.level), PROB(s.PROB), MAX_LEVEL(s.MAX_LEVEL), root(s.root) {}
57
63 inline skip_list& operator=(const skip_list& s) {
64 level = s.level;
65 PROB = s.PROB;
66 MAX_LEVEL = s.MAX_LEVEL;
67 root = s.root;
68 return *this;
69 }
70
74 inline ~skip_list() noexcept {}
75
80 inline void insert(T key) {
81 std::shared_ptr<node> head = root;
82 std::vector<std::shared_ptr<node>> update(MAX_LEVEL + 1, nullptr);
83
84 for (int i = level; i >= 0; i--) {
85 while (head->next[i] != nullptr && head->next[i]->key < key) {
86 head = head->next[i];
87 }
88 update[i] = head;
89 }
90
91 head = head->next[0];
92 if (!head || head->key != key) {
93 int lvl = rand_lvl();
94 if (lvl > level) {
95 for (int i = level + 1; i < lvl + 1; i++) {
96 update[i] = root;
97 }
98 level = lvl;
99 }
100
101 std::shared_ptr<node> nn = std::make_shared<node>(key, lvl);
102 for (int i = 0; i <= lvl; i++) {
103 nn->next[i] = update[i]->next[i];
104 update[i]->next[i] = nn;
105 }
106 }
107 }
108
109 class Iterator;
110
116 inline Iterator begin() { return Iterator(root->next[0]); }
117
123 inline Iterator end() { return Iterator(nullptr); }
124
129 inline void remove(T key) {
130 std::shared_ptr<node> x = root;
131 std::vector<std::shared_ptr<node>> update(MAX_LEVEL + 1, nullptr);
132
133 for (int64_t i = level; i >= 0; i--) {
134 while (x->next[i] && x->next[i]->key < key) {
135 x = x->next[i];
136 }
137 update[i] = x;
138 }
139
140 x = x->next[0];
141 if (x && x->key == key) {
142 for (int64_t i = 0; i <= level; i++) {
143 if (update[i]->next[i] != x) {
144 break;
145 }
146 update[i]->next[i] = x->next[i];
147 }
148 while (level > 0 && root->next[level] == nullptr) {
149 level--;
150 }
151 }
152 }
153
159 inline bool search(T key) {
160 std::shared_ptr<node> x = root;
161 for (int64_t i = level; i >= 0; i--) {
162 while (x->next[i] && x->next[i]->key < key) {
163 x = x->next[i];
164 }
165 }
166 x = x->next[0];
167 if (x && x->key == key) {
168 return true;
169 }
170 return false;
171 }
172
177
178#ifdef ENABLE_LIST_VISUALIZATION
179 inline void visualize() {
180 std::string generated = this->generate();
181 linked_list_visualization::visualize(generated);
182 }
183#endif
184
188 inline friend std::ostream& operator<<(std::ostream& out, skip_list<T>& l) {
189 std::shared_ptr<node> root = l.root;
190 out << "{";
191 for (int i = 0; i <= l.level; i++) {
192 out << i << ": ";
193 std::shared_ptr<node> curr = l.root->next[i];
194 while (curr != nullptr) {
195 out << curr->key << " ";
196 curr = curr->next[i];
197 }
198 out << '\n';
199 }
200 out << "}" << '\n';
201 return out;
202 }
203
204 private:
205 int MAX_LEVEL{};
206 float PROB{};
207
213 struct node {
214 T key;
215 std::vector<std::shared_ptr<node>> next;
216 node(T key, int level, void* value = nullptr) : key(key) {
217 for (int i = 0; i < level + 1; i++) {
218 next.push_back(nullptr);
219 }
220 }
221 };
222
223 int rand_lvl() {
224 float r = (float)rand() / RAND_MAX;
225 int lvl = 0;
226 while (r < PROB && lvl < MAX_LEVEL) {
227 lvl++;
228 r = (float)rand() / RAND_MAX;
229 }
230 return lvl;
231 }
232
233 int level{0};
234 std::shared_ptr<node> root;
235
236 std::string generate_node(std::string node_val, int levs) {
237 std::string gen;
238 gen += node_val;
239 gen += " [label=\"<";
240 gen += std::to_string(levs);
241 gen += "> ";
242 gen += node_val;
243 for (int i = levs - 1; i >= 0; i--) {
244 gen += " | <";
245 gen += std::to_string(i);
246 gen += "> ";
247 gen += node_val;
248 }
249 gen += "\"];";
250 gen += '\n';
251 return gen;
252 }
253
254 std::string generate_edge(std::string prev_val, std::string curr_val, int lev) {
255 std::string gen;
256 gen += prev_val;
257 gen += ':';
258 gen += std::to_string(lev);
259 gen += " -> ";
260 gen += curr_val;
261 gen += ':';
262 gen += std::to_string(lev);
263 gen += " ;\n";
264 return gen;
265 }
266
267 std::string generate() {
268 std::string gen;
269 gen += "rankdir=LR;";
270 gen += '\n';
271 gen += "node [shape=record;]";
272 gen += '\n';
273 std::unordered_set<std::string> S;
274 int m_level = std::min(level, (int)root->next.size()); // See if this is a parameter
275 gen += generate_node("root", m_level + 1);
276 gen += generate_node("NULL", m_level + 1);
277 gen += generate_edge("root", "NULL", m_level + 1);
278 for (int i = m_level; i >= 0; i--) {
279 std::shared_ptr<node> head = root;
280 head = head->next[i];
281 std::string prev_val = "root";
282 std::string head_key;
283 while (head) {
284 if (std::is_same_v<T, std::string>) {
285 head_key = head->key;
286 } else {
287 head_key = to_string(head->key);
288 }
289 if (S.find(head_key) == S.end()) {
290 S.insert(head_key);
291 gen += generate_node(head_key, i);
292 }
293 gen += generate_edge(prev_val, head_key, i);
294 prev_val = head_key;
295 head = head->next[i];
296 }
297 gen += generate_edge(prev_val, "NULL", i);
298 }
299 return gen;
300 }
301};
302
306template <typename T> class skip_list<T>::Iterator {
307 private:
308 std::shared_ptr<node> ptr;
309
310 public:
315 explicit Iterator(std::shared_ptr<node> ptr) noexcept : ptr(ptr) {}
316
323 Iterator& operator=(std::shared_ptr<node> current) {
324 this->ptr = current;
325 return *(this);
326 }
327
334 if (ptr != nullptr) {
335 ptr = ptr->next[0];
336 }
337 return *(this);
338 }
339
346 Iterator it = *this;
347 ++*(this);
348 return it;
349 }
350
357 bool operator!=(const Iterator& it) { return ptr != it.ptr; }
358
364 T operator*() { return ptr->key; }
365};
366
367#endif
Iterator class.
Definition skip_list.h:306
Iterator operator++(int)
operator ++ for type Iterator
Definition skip_list.h:345
T operator*()
operator * for type Iterator
Definition skip_list.h:364
bool operator!=(const Iterator &it)
operator != for type Iterator
Definition skip_list.h:357
Iterator & operator=(std::shared_ptr< node > current)
= operator for Iterator type*
Definition skip_list.h:323
Iterator & operator++()
operator ++
Definition skip_list.h:333
Iterator(std::shared_ptr< node > ptr) noexcept
Construct a new Iterator object.
Definition skip_list.h:315
skip_list(int MAX_LEVEL, float PROB)
skip_list constructor.
Definition skip_list.h:29
Iterator end()
pointer that points to the last element of the list
Definition skip_list.h:123
void remove(T key)
remove function.
Definition skip_list.h:129
~skip_list() noexcept
Destroy the skip list object.
Definition skip_list.h:74
skip_list & operator=(const skip_list &s)
operator = for the skip_list class
Definition skip_list.h:63
skip_list(const skip_list &s)
Copy constructor for the skip_list class.
Definition skip_list.h:55
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:188
Iterator begin()
pointer that points to the first element of the list
Definition skip_list.h:116
void insert(T key)
insert function.
Definition skip_list.h:80
bool search(T key)
search function.
Definition skip_list.h:159