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

247 lines
6.0 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 struccture for fast searching and insertion (O(log(n)))
* @details
2020-07-07 17:30:42 +08:00
* A skip list is a data structure that is used for storing a sorted list of items with a
2020-07-11 01:10:21 +08:00
* help of hierarchy of linked lists that connect increasingly sparse subsequences of the items
2020-07-07 17:30:42 +08:00
*
* References used: [GeeksForGeek](https://www.geeksforgeeks.org/skip-list/), [OpenGenus](https://iq.opengenus.org/skip-list) for PseudoCode and Code
2020-07-11 01:11:20 +08:00
* @author enqidu
2020-07-11 01:10:21 +08:00
* .
2020-07-07 17:30:42 +08:00
*/
#include <iostream>
#include <vector>
2020-07-07 23:22:32 +08:00
#include <cstring>
2020-07-07 22:20:21 +08:00
#include <ctime>
2020-07-07 18:54:44 +08:00
2020-07-07 18:04:44 +08:00
using std::vector;
using std::endl;
2020-07-07 17:30:42 +08:00
2020-07-11 00:39:33 +08:00
#define MAX_LEVEL 2 ///< Maximum level of skip list
#define 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*...]
*/
2020-07-07 22:16:38 +08:00
struct Node {
2020-07-07 23:17:37 +08:00
int key;
2020-07-09 00:46:50 +08:00
// pointer of value
2020-07-07 17:30:42 +08:00
void* value;
2020-07-11 00:39:33 +08:00
// Forward Array points to the neighbour (right)
// nodes of the given one in all levels
2020-07-07 17:30:42 +08:00
vector<Node*> forward;
2020-07-11 00:39:33 +08:00
// Constructor of the node
2020-07-07 17:30:42 +08:00
Node(int key, int level, void* value);
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-07 23:55:47 +08:00
* Creates node with provided key, level and value
2020-07-11 00:39:33 +08:00
* @param key is number that is used for comparision
* @param level is the maximum level node's going to added
2020-07-07 23:17:37 +08:00
*/
2020-07-07 17:30:42 +08:00
Node::Node(int key, int level, void* value) {
this->key = key;
2020-07-07 23:55:47 +08:00
//Initialization of forward vector
2020-07-07 22:16:38 +08:00
for (int i = 0; i < (level+1); i++){
2020-07-07 23:17:37 +08:00
forward.push_back(nullptr);
2020-07-07 17:30:42 +08:00
}
2020-07-07 18:29:08 +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
2020-07-07 23:55:47 +08:00
*/
2020-07-07 17:30:42 +08:00
class SkipList {
2020-07-11 00:39:33 +08:00
// Maximum level of the skiplist
2020-07-07 17:30:42 +08:00
int level;
2020-07-11 00:39:33 +08:00
// Pointer to the header node
2020-07-07 17:30:42 +08:00
Node *header;
public:
SkipList();
int randomLevel();
void insertElement(int, void*);
void deleteElement(int);
void* searchElement(int);
void displayList();
2020-07-07 21:24:13 +08:00
~SkipList();
2020-07-07 18:29:08 +08:00
};
2020-07-07 21:24:13 +08:00
2020-07-07 23:59:54 +08:00
/**
2020-07-11 00:39:33 +08:00
* Skeep List constructor. Initializes header, start
* Node for searching in the list
2020-07-07 23:17:37 +08:00
*/
2020-07-07 17:30:42 +08:00
SkipList::SkipList() {
level = 0;
2020-07-07 23:55:47 +08:00
// Header initialization
2020-07-07 23:17:37 +08:00
header = new Node(-1, MAX_LEVEL, nullptr);
2020-07-07 18:29:08 +08:00
}
2020-07-07 18:04:44 +08:00
2020-07-07 23:59:54 +08:00
/**
* Destructor for skiplist class
*/
2020-07-07 21:24:13 +08:00
SkipList::~SkipList(){
for(int i=0; i <= level; i++) {
Node *node = header->forward[i];
Node* temp;
2020-07-07 23:17:37 +08:00
while(node != nullptr) {
2020-07-07 21:24:13 +08:00
temp = node;
node = node->forward[i];
delete temp;
}
}
2020-07-07 22:16:38 +08:00
delete header;
2020-07-07 21:24:13 +08:00
}
2020-07-07 18:48:30 +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
* Returns random level of the skip list.
* Every higher level is 2 times less likely.
* @return lvl: random level for skip list;
2020-07-07 17:30:42 +08:00
*/
int SkipList::randomLevel() {
int lvl = 0;
2020-07-07 23:17:37 +08:00
while(static_cast<float>(std::rand())/RAND_MAX < PROBABILITY && lvl < MAX_LEVEL) lvl++;
2020-07-07 17:30:42 +08:00
return lvl;
2020-07-07 18:29:08 +08:00
}
2020-07-07 17:30:42 +08:00
2020-07-07 23:17:37 +08:00
2020-07-07 23:59:54 +08:00
/**
2020-07-07 23:17:37 +08:00
* Inserts elements with given key and value;
* It's level is computed by randomLevel() function.
2020-07-11 00:39:33 +08:00
* @param key is number that is used for comparision
* @param value pointer to a value, that can be any type
2020-07-07 23:17:37 +08:00
*/
2020-07-07 17:30:42 +08:00
void SkipList::insertElement(int key, void* value) {
2020-07-07 20:51:47 +08:00
std::cout << "Inserting" << key << "...";
2020-07-07 17:30:42 +08:00
Node *x = header;
2020-07-07 23:17:37 +08:00
Node *update[MAX_LEVEL+1];
memset(update, 0, sizeof(Node*)*(MAX_LEVEL+1));
2020-07-07 17:30:42 +08:00
for(int i = level; i >= 0; i--) {
2020-07-07 23:17:37 +08:00
while(x->forward[i] != nullptr && x->forward[i]->key < key) x = x->forward[i];
2020-07-07 17:30:42 +08:00
update[i] = x;
}
x = x->forward[0];
2020-07-07 23:17:37 +08:00
bool doesnt_exist = (x == nullptr || x->key != key);
2020-07-07 17:30:42 +08:00
if (doesnt_exist) {
int rlevel = randomLevel();
if(rlevel > level) {
for(int i=level+1;i<rlevel+1;i++) update[i] = header;
2020-07-09 00:47:43 +08:00
// Update current level
2020-07-07 17:30:42 +08:00
level = rlevel;
}
Node* n = new Node(key, rlevel, value);
for(int i=0;i<=rlevel;i++) {
n->forward[i] = update[i]->forward[i];
update[i]->forward[i] = n;
}
2020-07-07 20:51:47 +08:00
std::cout << "Inserted" << endl;
2020-07-07 17:30:42 +08:00
} else {
2020-07-07 20:51:47 +08:00
std::cout << "Exists" << endl;
2020-07-07 17:30:42 +08:00
}
2020-07-07 18:29:08 +08:00
}
2020-07-07 18:04:44 +08:00
2020-07-07 23:59:54 +08:00
/**
2020-07-11 00:39:33 +08:00
* Deletes an element by key and prints if has been removed successfully
* @param key is number that is used for comparision.
2020-07-07 23:58:10 +08:00
*/
2020-07-11 00:39:33 +08:00
void SkipList::deleteElement(int key) {
2020-07-07 17:30:42 +08:00
Node *x = header;
2020-07-07 23:17:37 +08:00
Node *update[MAX_LEVEL+1];
memset(update, 0, sizeof(Node*)*(MAX_LEVEL+1));
2020-07-07 17:30:42 +08:00
for(int i = level; i >= 0; i--) {
2020-07-07 23:17:37 +08:00
while(x->forward[i] != nullptr && x->forward[i]->key < key) x = x->forward[i];
2020-07-07 17:30:42 +08:00
update[i] = x;
}
x = x->forward[0];
2020-07-07 23:17:37 +08:00
bool doesnt_exist = (x == nullptr || x->key != key);
2020-07-07 17:30:42 +08:00
if(!doesnt_exist) {
for(int i=0;i<=level;i++) {
if(update[i]->forward[i] != x) break;
update[i]->forward[i] = x->forward[i];
}
2020-07-09 00:47:43 +08:00
/* Remove empty levels*/
2020-07-07 17:30:42 +08:00
while(level>0 && header->forward[level] == 0) level--;
2020-07-07 20:51:47 +08:00
std::cout << "Deleted" << endl;
2020-07-07 17:30:42 +08:00
} else {
2020-07-07 20:51:47 +08:00
std::cout << "Doesn't exist" << endl;
2020-07-07 17:30:42 +08:00
}
2020-07-07 18:29:08 +08:00
}
2020-07-07 17:30:42 +08:00
2020-07-07 23:59:54 +08:00
/**
2020-07-07 17:30:42 +08:00
* Searching element in skip list structure
2020-07-11 00:39:33 +08:00
* @param key is number that is used for comparision
* @return pointer to the value of the node
2020-07-07 17:30:42 +08:00
*/
void* SkipList::searchElement(int key) {
Node *x = header;
2020-07-07 20:51:47 +08:00
std::cout << "Searching for " + key << endl;
2020-07-07 17:30:42 +08:00
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){
2020-07-07 20:51:47 +08:00
std::cout << "Found" << endl;
2020-07-07 17:30:42 +08:00
return x->value;
} else {
2020-07-07 20:51:47 +08:00
std::cout << "Not Found" << endl;
2020-07-07 23:17:37 +08:00
return nullptr;
2020-07-07 17:30:42 +08:00
}
2020-07-07 18:29:08 +08:00
}
2020-07-07 17:30:42 +08:00
2020-07-07 23:58:10 +08:00
/*
2020-07-11 00:39:33 +08:00
* Display skip list level
2020-07-07 23:17:37 +08:00
*/
2020-07-07 17:30:42 +08:00
void SkipList::displayList() {
2020-07-07 20:51:47 +08:00
std::cout << "Displaying list:\n" << endl;
2020-07-07 17:30:42 +08:00
for(int i=0; i <= level; i++) {
Node *node = header->forward[i];
2020-07-07 20:51:47 +08:00
std::cout << "Level " << (i) << ": ";
2020-07-07 23:17:37 +08:00
while(node != nullptr) {
2020-07-07 20:51:47 +08:00
std::cout << node->key << " ";
2020-07-07 17:30:42 +08:00
node = node->forward[i];
}
2020-07-07 20:51:47 +08:00
std::cout << endl;
2020-07-07 17:30:42 +08:00
}
2020-07-07 18:29:08 +08:00
}
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
2020-07-07 23:17:37 +08:00
*/
2020-07-07 18:04:44 +08:00
int main()
{
2020-07-07 22:21:12 +08:00
std::srand(std::time(nullptr));
2020-07-07 18:29:08 +08:00
2020-07-07 17:30:42 +08:00
SkipList lst;
2020-07-07 23:17:37 +08:00
for (int j = 0; j < (1 << (MAX_LEVEL+1)); j++){
int k = (std::rand()%( 1 << (MAX_LEVEL+2)) + 1);
2020-07-07 17:30:42 +08:00
lst.insertElement(k, &j);
}
lst.displayList();
2020-07-07 18:04:44 +08:00
}