/** * @file skip_list.cpp * @brief Data structure for fast searching and insertion in \f$O(\log n)\f$ * time * @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) */ #include #include #include #include #include #include /** \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" /** * Node structure [Key][Node*, Node*...] */ struct Node { int key; ///< key integer void* value; ///< pointer of value std::vector> 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); } } }; /** * SkipList class implementation with basic methods */ class SkipList { int level; ///< Maximum level of the skiplist std::shared_ptr 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(new Node(-1, MAX_LEVEL)); } /** * 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(std::rand() / RAND_MAX) < PROBABILITY && lvl < MAX_LEVEL) lvl++; return lvl; } /** * 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 x = header; std::array, 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) { 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 n = std::shared_ptr(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; } } /** * 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 x = header; std::array, 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; } } /** * 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 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; } } /* * Display skip list level */ void displayList() { std::cout << "Displaying list:\n" << std::endl; for (int i = 0; i <= level; i++) { std::shared_ptr 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 /** * Main function: * Creates and inserts random 2^[number of levels] * elements into the skip lists and than displays it */ int main() { std::srand(std::time(nullptr)); data_structure::SkipList lst; 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); } lst.displayList(); }