Skip List: Alternative to Balanced Trees

Skip List is an advanced data structure that is used for storing a sorted list of elements.

Let’s suppose, you are working on a project called “Music Player”. You have a list of songs that you want to play in a specific order. You want to store these songs in a data structure that allows you to quickly search for a song, insert a new song, and delete a song. You also want to maintain the order of the songs. This is where the Skip List data structure comes in use.

What is a Skip List?

Skip List is a data structure that help us to search, insert, and delete elements in a sorted list. It is similar to a linked list, but with additional pointers that allow us to skip over some elements. This makes searching for an element faster than a linked list.

A Skip List is a probabilistic data structure, which means that the structure of the list is determined by random choices. The Skip List is a versatile data structure that can be used in a variety of applications, such as databases, search engines, and network routing algorithms.

How does a Skip List work?

Skip list has multiple levels. The bottom level is a sorted linked list that contains all the elements. Then, each higher level contains a subset of the elements from the lower level. The higher levels have pointers that allow us to skip over some elements. This makes searching for an element faster than a linked list.

Representation of Skip List

A Skip List is represented as a series of linked lists, where each list is a level of the Skip List. Each node in the Skip List contains a key and a value. The key is used to sort the elements in the list, and the value is the data associated with the key.

Each node also contains pointers to the next node in the same level, and pointers to the next node in the level below. The top level of the Skip List contains only one node, which is the head of the list. The head node contains pointers to the first node in each level of the Skip List.

Skip List

Types of Skip List

There are more than one type of Skip Lists:

  • Randomized Skip List: In a randomized skip list, the elements promoted to higher levels are chosen randomly. This makes the structure of the skip list unpredictable.
  • Deterministic Skip List:In the deterministic skip list, the elements promoted to higher levels are chosen based on a deterministic rule. This makes the structure of the skip list predictable. For example, in a deterministic skip list, every 2nd element is promoted to the next level.

Operations on Skip List

A Skip List supports the following operations:

  • Search: Search for an element in the Skip List.
  • Insert: Insert an element into the Skip List.
  • Delete: Delete an element from the Skip List.

Implementing a Skip List

A Skip List can be implemented using a linked list data structure. Each node in the Skip List contains a key, a value, and an array of pointers to the next node in each level. The Skip List also contains a head node that points to the first node in each level. Here is an example of a Skip List implemented in C, C++, Java and Python:

Algorithm to implement Skip List

In order to implement a Skip List, we need to follow these steps:





Create a Node structure, with key, value, and an array of pointers.Create a SkipList structure, with a head node and the level of the Skip List.Create a function to create a new node.Create a function to create a new Skip List.Create a function to generate a random level for a node.Create a function to insert a node into the Skip List.Create a function to display the Skip List.At last, create a main function to test the Skip List.

Example of Skip List

Following is an example of a Skip List implemented in C, C++, Java, and Python that demonstrates the insertion of elements into the Skip List and displays the Skip List:

CC++JavaPython

//C Program to implement Skip List#include <stdio.h>#include <stdlib.h>#include <limits.h>#include <time.h>#define MAX_LEVEL 6// Node structurestructNode{int key;structNode*forward[MAX_LEVEL];};// SkipList structurestructSkipList{structNode*header;int level;};// Create a nodestructNode*createNode(int key,int level){structNode*newNode =(structNode*)malloc(sizeof(structNode));
   newNode->key = key;for(int i =0; i < level; i++)
      newNode->forward[i]=NULL;return newNode;}// Create a SkipListstructSkipList*createSkipList(){structSkipList*list =(structSkipList*)malloc(sizeof(structSkipList));
   list->header =createNode(INT_MIN, MAX_LEVEL);
   list->level =0;return list;}// Generate random level for nodeintrandomLevel(){int level =0;while(rand()< RAND_MAX /2&& level < MAX_LEVEL)
      level++;return level;}// Insert a nodevoidinsertNode(structSkipList*list,int key){structNode*current = list->header;structNode*update[MAX_LEVEL];for(int i = list->level; i >=0; i--){while(current->forward[i]!=NULL&& current->forward[i]->key < key)
         current = current->forward[i];
      update[i]= current;}
   current = current->forward[0];if(current ==NULL|| current->key != key){int rlevel =randomLevel();if(rlevel > list->level){for(int i = list->level +1; i <= rlevel; i++)
            update[i]= list->header;
         list->level = rlevel;}structNode*newNode =createNode(key, rlevel);for(int i =0; i <= rlevel; i++){
         newNode->forward[i]= update[i]->forward[i];
         update[i]->forward[i]= newNode;}}}// Display the SkipListvoiddisplayList(structSkipList*list){printf("\nSkip List\n");for(int i =0; i <= list->level; i++){structNode*node = list->header->forward[i];printf("Level %d: ", i);while(node !=NULL){printf("%d ", node->key);
         node = node->forward[i];}printf("\n");}}intmain(){srand((unsigned)time(0));structSkipList*list =createSkipList();insertNode(list,3);insertNode(list,6);insertNode(list,7);insertNode(list,9);insertNode(list,12);insertNode(list,19);insertNode(list,17);insertNode(list,26);insertNode(list,21);insertNode(list,25);displayList(list);return0;}

Output

The output obtained is as follows −

Skip List
Level 0: 3 6 7 9 12 17 19 21 25 26 
Level 1: 6 9 12 17 21 26 
Level 2: 9 

Note: output may vary as the level of the Skip List is generated randomly.

Search Operation in Skip List

The search operation in a Skip List is similar to a linked list. We start from the top level and move to the next level if the key is greater than the current node. We continue this process until we find the key or reach the bottom level. If the key is found, we return the node; otherwise, we return NULL.

Algorithm

Following are steps to search for a key in a Skip List:





Start from the top level of the Skip List.Move to the next level if the key is greater than the current node.Continue this process until we find the key or reach the bottom level.If the key is found, return the node; otherwise, return NULL.

Example of Search Operation in Skip List

Let’s search for the key 12 in the Skip List. The search operation is as follows:

CC++JavaPython

//C Program to search for a key in Skip List#include <stdio.h>#include <stdlib.h>#include <limits.h>#include <time.h>#define MAX_LEVEL 6// Node structurestructNode{int key;structNode*forward[MAX_LEVEL];};// SkipList structurestructSkipList{structNode*header;int level;};// Create a nodestructNode*createNode(int key,int level){structNode*newNode =(structNode*)malloc(sizeof(structNode));
   newNode->key = key;for(int i =0; i < level; i++)
      newNode->forward[i]=NULL;return newNode;}// Create a SkipListstructSkipList*createSkipList(){structSkipList*list =(structSkipList*)malloc(sizeof(structSkipList));
   list->header =createNode(INT_MIN, MAX_LEVEL);
   list->level =0;return list;}// Generate random level for nodeintrandomLevel(){int level =0;while(rand()< RAND_MAX /2&& level < MAX_LEVEL)
      level++;return level;}// Search for a keystructNode*searchNode(structSkipList*list,int key){structNode*current = list->header;for(int i = list->level; i >=0; i--){while(current->forward[i]!=NULL&& current->forward[i]->key < key)
         current = current->forward[i];}
   current = current->forward[0];if(current !=NULL&& current->key == key)return current;returnNULL;}// create nodevoidinsertNode(structSkipList*list,int key){structNode*current = list->header;structNode*update[MAX_LEVEL];for(int i = list->level; i >=0; i--){while(current->forward[i]!=NULL&& current->forward[i]->key < key)
          current = current->forward[i];
       update[i]= current;}
    current = current->forward[0];if(current ==NULL|| current->key != key){int rlevel =randomLevel();if(rlevel > list->level){for(int i = list->level +1; i <= rlevel; i++)
             update[i]= list->header;
          list->level = rlevel;}structNode*newNode =createNode(key, rlevel);for(int i =0; i <= rlevel; i++){
          newNode->forward[i]= update[i]->forward[i];
          update[i]->forward[i]= newNode;}}}intmain(){srand((unsigned)time(0));structSkipList*list =createSkipList();insertNode(list,3);insertNode(list,6);insertNode(list,7);insertNode(list,9);insertNode(list,12);insertNode(list,19);insertNode(list,17);insertNode(list,26);insertNode(list,21);insertNode(list,25);structNode*node =searchNode(list,12);if(node !=NULL)printf("Key found: %d\n", node->key);elseprintf("Key not found\n");return0;}

Output

The output obtained is as follows −

Key found: 12

Delete Operation in Skip List

The delete operation in a Skip List is similar to a linked list. We search for the key to be deleted and update the pointers to remove the node from the list. The delete operation is as follows:

Algorithm

Following are the steps to delete a key in a Skip List:





Search for the key to be deleted in the Skip List.Update the pointers to remove the node from the list.Repeat this process for all levels of the Skip List.

Example of Delete Operation in Skip List

Let’s delete the key 12 from the Skip List. The delete operation is as follows:

CC++JavaPython

//C Program to delete a key in Skip List#include <stdio.h>#include <stdlib.h>#include <limits.h>#include <time.h>#define MAX_LEVEL 6// Node structurestructNode{int key;structNode*forward[MAX_LEVEL];};// SkipList structurestructSkipList{structNode*header;int level;};// Create a nodestructNode*createNode(int key,int level){structNode*newNode =(structNode*)malloc(sizeof(structNode));
   newNode->key = key;for(int i =0; i < level; i++)
      newNode->forward[i]=NULL;return newNode;}// Create a SkipListstructSkipList*createSkipList(){structSkipList*list =(structSkipList*)malloc(sizeof(structSkipList));
   list->header =createNode(INT_MIN, MAX_LEVEL);
   list->level =0;return list;}// Generate random level for nodeintrandomLevel(){int level =0;while(rand()< RAND_MAX /2&& level < MAX_LEVEL)
      level++;return level;}// Search for a keystructNode*searchNode(structSkipList*list,int key){structNode*current = list->header;for(int i = list->level; i >=0; i--){while(current->forward[i]!=NULL&& current->forward[i]->key < key)
         current = current->forward[i];}
   current = current->forward[0];if(current !=NULL&& current->key == key)return current;returnNULL;}// Delete a keyvoiddeleteNode(structSkipList*list,int key){structNode*current = list->header;structNode*update[MAX_LEVEL];for(int i = list->level; i >=0; i--){while(current->forward[i]!=NULL&& current->forward[i]->key < key)
         current = current->forward[i];
      update[i]= current;}
   current = current->forward[0];if(current !=NULL&& current->key == key){for(int i =0; i <= list->level; i++){if(update[i]->forward[i]!= current)break;
         update[i]->forward[i]= current->forward[i];}free(current);while(list->level >0&& list->header->forward[list->level]==NULL)
         list->level--;}}// Insert a nodevoidinsertNode(structSkipList*list,int key){structNode*current = list->header;structNode*update[MAX_LEVEL];for(int i = list->level; i >=0; i--){while(current->forward[i]!=NULL&& current->forward[i]->key < key)
          current = current->forward[i];
       update[i]= current;}
    current = current->forward[0];if(current ==NULL|| current->key != key){int rlevel =randomLevel();if(rlevel > list->level){for(int i = list->level +1; i <= rlevel; i++)
             update[i]= list->header;
          list->level = rlevel;}structNode*newNode =createNode(key, rlevel);for(int i =0; i <= rlevel; i++){
          newNode->forward[i]= update[i]->forward[i];
          update[i]->forward[i]= newNode;}}}//display list voiddisplayList(structSkipList*list){printf("\nSkip List\n");for(int i =0; i <= list->level; i++){structNode*node = list->header->forward[i];printf("Level %d: ", i);while(node !=NULL){printf("%d ", node->key);
         node = node->forward[i];}printf("\n");}}intmain(){srand((unsigned)time(0));structSkipList*list =createSkipList();insertNode(list,3);insertNode(list,6);insertNode(list,7);insertNode(list,9);insertNode(list,12);insertNode(list,19);insertNode(list,17);insertNode(list,26);insertNode(list,21);insertNode(list,25);deleteNode(list,12);structNode*node =searchNode(list,12);printf("\nBefore deleting 12:\n");displayList(list);if(node !=NULL)printf("Key found: %d\n", node->key);elseprintf("Key not found:\n");printf("\nAfter deleting 12:\n");displayList(list);return0;}

Output

The output obtained is as follows −

Before deleting 12:

Skip List
Level 0: 3 6 7 9 17 19 21 25 26 
Level 1: 6 7 21 
Level 2: 6 
Key not found:

After deleting 12:

Skip List
Level 0: 3 6 7 9 17 19 21 25 26 
Level 1: 6 7 21 
Level 2: 6 

Time Complexity and Space Complexity of Skip List

  • The time complexity of search, insert, and delete operations in a Skip List is O(log n) on average.
  • The time complexity of these operations is the same as that of a balanced binary search tree.
  • The space complexity of a Skip List is O(n).

Applications of Skip List

The Skip List data structure is used in the following applications:

  • Database Indexing: Skip Lists are used in databases to index data efficiently.
  • Search Engines: Skip Lists are also used in search engines to store and retrieve web pages.
  • Network Routing Algorithms: This data structure also used in network routing algorithms to find the shortest path between two nodes.

Advantages of Skip List

Following are the advantages of Skip List −

  • Efficient Operations: Skip Lists provide efficient search, insert, and delete operations.
  • Simple Implementation: Skip Lists are easy to implement compared to other data structures like AVL trees and Red-Black trees.
  • Space Efficiency: Skip Lists are space-efficient and require less memory compared to other data structures.

Disadvantages of Skip List

Following are the disadvantages of Skip List −

  • Complexity: Skip Lists are complex data structures compared to linked lists.
  • Randomness: The performance of Skip Lists depends on the randomness of the levels.

Conclusion

In this tutorial, we learned about the Skip List data structure, its operations, and its implementation in C, C++, Java, and Python. Skip Lists are efficient data structures that provide fast search, insert, and delete operations. Skip Lists are used in various applications like database indexing, search engines, and network routing algorithms.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *