TheAlgorithms-C-Plus-Plus/data_structures/skip_list.cpp

220 lines
6.4 KiB
C++
Raw Normal View History

2020-07-08 00:29:37 +08:00
/**
2020-07-11 01:10:21 +08:00
* @file skip_list.cpp
* @brief Data structure for fast searching and insertion in \f$O(\log n)\f$
* time
2020-07-11 01:10:21 +08:00
* @details
* A skip list is a data structure that is used for storing a sorted list of
* items with a help of hierarchy of linked lists that connect increasingly
* sparse subsequences of the items
*
* References used: [GeeksForGeek](https://www.geeksforgeeks.org/skip-list/),
* [OpenGenus](https://iq.opengenus.org/skip-list) for PseudoCode and Code
* @author [enqidu](https://github.com/enqidu)
* @author [Krishna Vedala](https://github.com/kvedala)
*/
2020-07-07 17:30:42 +08:00
#include <array>
#include <cstring>
#include <ctime>
2020-07-07 17:30:42 +08:00
#include <iostream>
#include <memory>
2020-07-07 17:30:42 +08:00
#include <vector>
2020-07-07 18:54:44 +08:00
/** \namespace data_structure
* \brief Data-structure algorithms
*/
namespace data_structure {
constexpr int MAX_LEVEL = 2; ///< Maximum level of skip list
constexpr float PROBABILITY = 0.5; ///< Current probability for "coin toss"
2020-07-07 17:30:42 +08:00
2020-07-07 23:59:54 +08:00
/**
2020-07-07 17:30:42 +08:00
* Node structure [Key][Node*, Node*...]
*/
struct Node {
int key; ///< key integer
void* value; ///< pointer of value
std::vector<std::shared_ptr<Node>>
forward; ///< nodes of the given one in all levels
/**
* Creates node with provided key, level and value
* @param key is number that is used for comparision
* @param level is the maximum level node's going to added
*/
Node(int key, int level, void* value = nullptr) : key(key) {
// Initialization of forward vector
for (int i = 0; i < (level + 1); i++) {
forward.push_back(nullptr);
}
}
2020-07-07 18:04:44 +08:00
};
2020-07-07 17:30:42 +08:00
2020-07-07 23:59:54 +08:00
/**
2020-07-11 00:39:33 +08:00
* SkipList class implementation with basic methods
*/
class SkipList {
int level; ///< Maximum level of the skiplist
std::shared_ptr<Node> header; ///< Pointer to the header node
public:
/**
* Skip List constructor. Initializes header, start
* Node for searching in the list
*/
SkipList() {
level = 0;
// Header initialization
header = std::shared_ptr<Node>(new Node(-1, MAX_LEVEL));
}
2020-07-07 21:24:13 +08:00
/**
* Returns random level of the skip list.
* Every higher level is 2 times less likely.
* @return random level for skip list
*/
int randomLevel() {
int lvl = 0;
while (static_cast<float>(std::rand() / RAND_MAX) < PROBABILITY &&
lvl < MAX_LEVEL)
lvl++;
return lvl;
}
2020-07-07 18:04:44 +08:00
/**
* Inserts elements with given key and value;
* It's level is computed by randomLevel() function.
* @param key is number that is used for comparision
* @param value pointer to a value, that can be any type
*/
void insertElement(int key, void* value) {
std::cout << "Inserting" << key << "...";
std::shared_ptr<Node> x = header;
std::array<std::shared_ptr<Node>, MAX_LEVEL + 1> update;
update.fill(nullptr);
for (int i = level; i >= 0; i--) {
while (x->forward[i] != nullptr && x->forward[i]->key < key)
x = x->forward[i];
update[i] = x;
}
2020-07-07 18:48:30 +08:00
x = x->forward[0];
bool doesnt_exist = (x == nullptr || x->key != key);
if (doesnt_exist) {
int rlevel = randomLevel();
if (rlevel > level) {
for (int i = level + 1; i < rlevel + 1; i++) update[i] = header;
// Update current level
level = rlevel;
}
std::shared_ptr<Node> n =
std::shared_ptr<Node>(new Node(key, rlevel, value));
for (int i = 0; i <= rlevel; i++) {
n->forward[i] = update[i]->forward[i];
update[i]->forward[i] = n;
}
std::cout << "Inserted" << std::endl;
} else {
std::cout << "Exists" << std::endl;
}
2020-07-07 17:30:42 +08:00
}
/**
* Deletes an element by key and prints if has been removed successfully
* @param key is number that is used for comparision.
*/
void deleteElement(int key) {
std::shared_ptr<Node> x = header;
std::array<std::shared_ptr<Node>, MAX_LEVEL + 1> update;
update.fill(nullptr);
for (int i = level; i >= 0; i--) {
while (x->forward[i] != nullptr && x->forward[i]->key < key)
x = x->forward[i];
update[i] = x;
}
x = x->forward[0];
bool doesnt_exist = (x == nullptr || x->key != key);
if (!doesnt_exist) {
for (int i = 0; i <= level; i++) {
if (update[i]->forward[i] != x)
break;
update[i]->forward[i] = x->forward[i];
}
/* Remove empty levels*/
while (level > 0 && header->forward[level] == nullptr) level--;
std::cout << "Deleted" << std::endl;
} else {
std::cout << "Doesn't exist" << std::endl;
2020-07-07 17:30:42 +08:00
}
}
/**
* Searching element in skip list structure
* @param key is number that is used for comparision
* @return pointer to the value of the node
*/
void* searchElement(int key) {
std::shared_ptr<Node> x = header;
std::cout << "Searching for " << key << std::endl;
for (int i = level; i >= 0; i--) {
while (x->forward[i] && x->forward[i]->key < key) x = x->forward[i];
}
x = x->forward[0];
if (x && x->key == key) {
std::cout << "Found" << std::endl;
return x->value;
} else {
std::cout << "Not Found" << std::endl;
return nullptr;
}
2020-07-07 17:30:42 +08:00
}
2020-07-07 23:17:37 +08:00
/*
* Display skip list level
*/
void displayList() {
std::cout << "Displaying list:\n" << std::endl;
for (int i = 0; i <= level; i++) {
std::shared_ptr<Node> node = header->forward[i];
std::cout << "Level " << (i) << ": ";
while (node != nullptr) {
std::cout << node->key << " ";
node = node->forward[i];
}
std::cout << std::endl;
}
}
};
} // namespace data_structure
2020-07-07 23:17:37 +08:00
2020-07-07 23:59:54 +08:00
/**
2020-07-07 23:17:37 +08:00
* Main function:
* Creates and inserts random 2^[number of levels]
* elements into the skip lists and than displays it
*/
int main() {
2020-07-07 22:21:12 +08:00
std::srand(std::time(nullptr));
2020-07-07 18:29:08 +08:00
data_structure::SkipList lst;
2020-07-07 17:30:42 +08:00
for (int j = 0; j < (1 << (data_structure::MAX_LEVEL + 1)); j++) {
int k = (std::rand() % (1 << (data_structure::MAX_LEVEL + 2)) + 1);
lst.insertElement(k, &j);
2020-07-07 17:30:42 +08:00
}
lst.displayList();
}