Introduced by William Pugh in 1989, a skip list data structure is a randomized probabilistic data structure that stores data level-wise. The lowest level of the skip list has all the elements, and as we move level-wise upward, a skip list skips the elements from the previous layer. The main advantage of a skip list is that it provides efficient search and fast retrieval and deletion with an average time complexity of
In this Answer, we will discuss implementing a skip list in C++. For this implementation, we will cover essential functions such as inserting a key, deleting a key, and searching for a key.
Node
classThe Node
class consists of the data and vector of the nodes. We initialize the vector with the size of the level by the null value. Each node in the skip list allows for efficient traversal by storing the pointers.
const int maxNumberOfLevel = 5; // Maximum Level of the skip listclass Node{public:int data;vector<Node*> next; // To maintain the levels of the skip listNode(int data, int Level) : data(data), next(Level + 1, nullptr) {} // declaring the data and the level of the node};
skipList
classThe SkipList
will consist of the head pointer and the number of levels. The functions it includes are insert
, remove
, search
and display
. As you know, inserting and removing the skip list's value requires changing the skip list's structure. We will discuss these operations individually and show how we can maintain the skip list's structure and data consistently.
class skipList{private:Node* head;int Level;public:skipList();void insert(int data); // To insert the valuevoid remove(int data); // To delete the valuebool search(int data); // To search for a valuevoid display(); // Function to display a skip List};
constructor
of the skipList
classThe code for the constructor
of the skipList
class is given below. It consists of the head pointer and the level. Here we are initializing the skip list with the maximum number of levels.
skipList:: skipList(){head = new Node(0, maxNumberOfLevel); // Initializing the skip list with the max number of levelsLevel = 0; // At start the level is 0}
Insert
functionInsertion
in the skip list is based on the coin toss method that determines the number of levels for the inserting value. The insertion of a skip list is based on maintaining the sorted order of the skip list and the coin toss that decides the level of the inserted key. The code for the insertion function
is given below.
void skipList::insert(int data){int newLevel = 0;// Deciding the level of inserting node on the basis of coin tosswhile (newLevel < maxNumberOfLevel and (rand() % 2) == 1) // here rand()%2 is doing the coin toss{newLevel++;}// Resizing the size of the levels to make place for the inserting valueif (Level < newLevel){head->next.resize(newLevel + 1, nullptr);Level = newLevel;}Node* current = head; // pointer to the head to traverse through the skip listvector<Node*> Update(Level + 1, nullptr); // To store the update node at eah level// Loop over the levels upto which we want the value to be insertedfor (int i = Level; i >= 0; i--){// Finding the place for the inserting valuewhile (current->next[i] and current->next[i]->data < data){current = current->next[i];}// Updating the level accordinglyUpdate[i] = current;}current = current->next[0]; // Moves the current to the next node at level 0if (current == nullptr or current->data != data) // if the current is null then it does not exit we need to insert the value{Node* newNode = new Node(data, Level);for (int i = 0; i <= newLevel; i++){newNode->next[i] = Update[i]->next[i];Update[i]->next[i] = newNode; // To insert the value at each level}cout << "Element " << data << " inserted successfully.\n";}else{cout << "Element " << data << " already exists.\n"; // Incase if value already exists}}
Remove
functionIn skip lists, we remove the value from each layer of the skipList
class. After removing the value, we ensure that pointers are set accordingly. There will be a change in the structure after removing a key in the skip list. An example of deleting a value in the skip list is given here:
void skipList::remove(int data){// Function to remove valueNode* current = head; // start by setting a current pointer to the head nodevector<Node*> Update(Level + 1, nullptr); // Create an update vector to store the updated node at each level, Remember only those nodes will be updated where the value to be deleted is present.for (int i = Level; i >= 0; i--){while (current->next[i] and current->next[i]->data < data){current = current->next[i];}Update[i] = current; // Update array is keeping the track, where the changes should be made, after deleting the node.}current = current->next[0]; // Set the current pointer to the next node at level 0.if (current != nullptr and current->data == data) // If the value is present then delete the value{for (int i = 0; i <= Level; i++) // Deleting the value from each level{// Setting the pointersif (Update[i]->next[i] != current){break;}else{Update[i]->next[i] = current->next[i];}}delete current; // deleting the nodewhile (Level > 0 and head->next[Level] == nullptr) // decrement the level variable incase there is not any value at that level{Level--;}cout << "Element " << data << " deleted successfully."<<endl;}else // Incase the value does not exist{cout << "Element " << data << " not found."<<endl;}}
Search
functionThe efficient searching mechanism gives the skip list priority over the other data structure. While searching, it utilizes the advantage of skipping over large portions of the data from the upper layers. We check the element at every layer to search for the specific value by comparing the values and decide our following action, whether to move down, forward, or return from the function in case it has found the node with that value.
Look at this implementation of the search
function in a skip list:
bool skipList::search(int data){Node* current = head; // start by setting a current pointer to the head node to traverse through the skip listfor (int i = Level; i >= 0; i--) // Begin traversing from the top level and iteratively approaching the bottom of the skip list{while (current->next[i] and current->next[i]->data < data) // keep on moving forward if the value of the next node is less than the searching node otherwise move downward (handled by outer for loop){current = current->next[i]; // moving forward}}current = current->next[0]; // Move to the next of the node at level 0if (current != nullptr && current->data == data) // if value is found{cout << "Element " << data << " found.\n";return true;}else // Incase value does not exist{cout << "Element " << data << " not found.\n";return false;}}
Display
functionThe display
function provides us with the feasibility to analyze the state of the skip list at a specific stage. We can print the skip list data structure through this function after removing or inserting the data to check the effective changes in the structure.
void skipList::display(){cout << "skip List:"<< endl;for (int i = Level; i >= 0; i--) //{Node* current = head->next[i]; // Initializes the pointer to the first node of that levelcout << "Level " << i << ": ";while (current != nullptr) // Start displaying all the values present at that level{cout << current->data << " ";current = current->next[i]; // Moving to the right of the node}cout << endl;}}
Now we will test the skip list by performing various functions. You can edit it as well. Make edits to the following code to apply the concept that you have just learned.
int main(){skipList SkipList; // Creating the skip List// Inserting the Data in skip listSkipList.insert(10);SkipList.insert(20);SkipList.insert(30);SkipList.insert(40);SkipList.insert(50);// Display skip list after inserting the dataSkipList.display();// Searching for the keySkipList.search(20);SkipList.search(40);// Deleting the keySkipList.remove(20);SkipList.remove(40);// Display the skip list after removing the dataSkipList.display();return 0;}
We use skip lists where we need efficient retrieval of the data. They enable fast insertion and deletion of a value. In this Answer, we learned how to implement a skip list in C++. It might be challenging to understand for the first time, but with practice, you will be able to implement skip lists independently.
Which data structure is commonly used as the base structure for implementing skip lists?
Linked list
Binary search tree
Array
Hash table
Free Resources