Implementation of skip list in C++.

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 O(logn)O(logn).

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.

The Node class

The 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 list
class Node
{
public:
int data;
vector<Node*> next; // To maintain the levels of the skip list
Node(int data, int Level) : data(data), next(Level + 1, nullptr) {} // declaring the data and the level of the node
};

The skipList class

The 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 value
void remove(int data); // To delete the value
bool search(int data); // To search for a value
void display(); // Function to display a skip List
};

The constructor of the skipList class

The 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 levels
Level = 0; // At start the level is 0
}

Insert function

Insertion 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 toss
while (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 value
if (Level < newLevel)
{
head->next.resize(newLevel + 1, nullptr);
Level = newLevel;
}
Node* current = head; // pointer to the head to traverse through the skip list
vector<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 inserted
for (int i = Level; i >= 0; i--)
{
// Finding the place for the inserting value
while (current->next[i] and current->next[i]->data < data)
{
current = current->next[i];
}
// Updating the level accordingly
Update[i] = current;
}
current = current->next[0]; // Moves the current to the next node at level 0
if (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 function

In 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 value
Node* current = head; // start by setting a current pointer to the head node
vector<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 pointers
if (Update[i]->next[i] != current)
{
break;
}
else
{
Update[i]->next[i] = current->next[i];
}
}
delete current; // deleting the node
while (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 function

The 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 list
for (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 0
if (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 function

The 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 level
cout << "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;
}
}

Working with the skip list

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 list
SkipList.insert(10);
SkipList.insert(20);
SkipList.insert(30);
SkipList.insert(40);
SkipList.insert(50);
// Display skip list after inserting the data
SkipList.display();
// Searching for the key
SkipList.search(20);
SkipList.search(40);
// Deleting the key
SkipList.remove(20);
SkipList.remove(40);
// Display the skip list after removing the data
SkipList.display();
return 0;
}

Conclusion

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.

Q

Which data structure is commonly used as the base structure for implementing skip lists?

A)

Linked list

B)

Binary search tree

C)

Array

D)

Hash table

Free Resources

Copyright ©2025 Educative, Inc. All rights reserved