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
|
|
|
|
* help of hierarchy of linked lists that connect increasingly sparse subsequences of the items
|
|
|
|
*
|
2020-07-07 23:17:37 +08:00
|
|
|
* References used: GeeksForGeeks skip list code, https://iq.opengenus.org/skip-list/ Code and PseudoCode.
|
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 namespace std;
|
|
|
|
using std::vector;
|
|
|
|
using std::endl;
|
2020-07-07 17:30:42 +08:00
|
|
|
|
2020-07-07 23:17:37 +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
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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-07 23:55:47 +08:00
|
|
|
//pointer of value
|
2020-07-07 17:30:42 +08:00
|
|
|
void* value;
|
2020-07-07 23:55:47 +08:00
|
|
|
//Forward Array
|
2020-07-07 17:30:42 +08:00
|
|
|
vector<Node*> forward;
|
|
|
|
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:17:37 +08:00
|
|
|
/**
|
2020-07-07 23:55:47 +08:00
|
|
|
* Creates node with provided key, level and value
|
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:55:47 +08:00
|
|
|
/**
|
|
|
|
* SkipList class
|
|
|
|
*/
|
2020-07-07 17:30:42 +08:00
|
|
|
class SkipList {
|
|
|
|
int level;
|
|
|
|
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:55:47 +08:00
|
|
|
/**
|
|
|
|
* Skeep List constructor
|
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 18:48:30 +08:00
|
|
|
|
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
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns random level for skip list;
|
|
|
|
*/
|
|
|
|
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
|
|
|
|
|
|
|
/**
|
|
|
|
* Inserts elements with given key and value;
|
|
|
|
* It's level is computed by randomLevel() function.
|
|
|
|
*/
|
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-07 23:55:47 +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 20:51:47 +08:00
|
|
|
/**Delete document by key*/
|
2020-07-07 17:30:42 +08:00
|
|
|
void SkipList::deleteElement(int key)
|
|
|
|
{
|
|
|
|
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];
|
|
|
|
}
|
|
|
|
/*Remove empty levels*/
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Searching element in skip list structure
|
|
|
|
*/
|
|
|
|
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:17:37 +08:00
|
|
|
/**
|
|
|
|
* Display skip list level wise
|
|
|
|
*/
|
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
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Main function:
|
|
|
|
* Creates and inserts random 2^[number of levels] elements into the skip lists and than displays it
|
|
|
|
*/
|
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
|
|
|
|
|
|
|
}
|