Skip List

A skip list is a probabilistic data structure that provides logarithmic time operations for sequential access and search. It consists of successive “layers” of linked lists that connect increasingly sparse subsequences of elements.

Java example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class Node {
  int value;
  Node next, down; 
}

public class SkipList {

  private Node head;
  private int maxLevel;

  public boolean search(int value) {
    Node current = head;
    for (int i = maxLevel; i >= 0; i--) {
      while (current.next != null && current.next.value < value) {
        current = current.next; 
      }
      if (current.value == value) {
        return true; 
      }
      current = current.down;
    }
    return false;
  }
  
  public void insert(int value) {
    int level = randomLevel();
    Node newNode = new Node(value, level);
    Node current = head;

    // Insert node at each level
  }

}

C++ example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
struct Node {
  int value;
  Node *next, *down;
};

class SkipList {
private:
  Node* head;
  int maxLevel;
  
public:
  bool search(int value) {
    Node *curr = head;
    for (int i = maxLevel; i >= 0; i--) {
      while (curr->next && curr->next->value < value) 
        curr = curr->next;
      if (curr->value == value) return true;
      curr = curr->down;
    }
    return false;
  }  

  void insert(int value) {
    int level = randomLevel();
    Node* newNode = new Node(value, level);
    Node* curr = head;

    // Insert logic
  }
};

Python example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import random

class Node:

  def __init__(self, value, max_level):
    self.value = value
    self.next = [None] * (max_level + 1)
    self.down = None

class SkipList:

  def __init__(self):
    self.max_level = 0
    self.head = Node(-1, self.max_level)

  def insert(self, value):
    level = random.randint(0, self.max_level+1)
    newNode = Node(value, level)  
    current = self.head

    # Insert logic    
  
  def search(self, value):
    current = self.head
    for i in range(self.max_level, -1, -1):
      while current.next[i] and current.next[i].value < value:
        current = current.next[i]  
      if current.value == value:
        return True 
    return False

Skip lists provide probabilistic balancing for fast search, insert, delete in O(log n) time.

A Skip List is a data structure that allows fast search within an ordered sequence of elements. It does this by maintaining multiple layers of linked lists, where each layer skips over a fixed number of elements. This hierarchical design allows Skip Lists to achieve the same logarithmic time complexity for search, insert, and delete operations as balanced trees like AVL or Red-Black trees. However, Skip Lists are easier to implement and can be more efficient in practice.

Java Code for Skip List

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import java.util.Random;

class Node {
    int value;
    Node[] next;

    public Node(int value, int level) {
        this.value = value;
        this.next = new Node[level];
    }
}

public class SkipList {
    private Node head;
    private int maxLevel;
    private Random rand = new Random();

    public SkipList() {
        head = new Node(0, 16);  // Max 16 levels
        maxLevel = 1;
    }

    public void insert(int value) {
        Node[] update = new Node[maxLevel];
        Node x = head;
        
        // Search in the list
        for (int i = maxLevel - 1; i >= 0; i--) {
            while (x.next[i] != null && x.next[i].value < value) {
                x = x.next[i];
            }
            update[i] = x;
        }

        int level = rand.nextInt(16) + 1;
        if (level > maxLevel) {
            for (int i = maxLevel; i < level; i++) {
                update[i] = head;
            }
            maxLevel = level;
        }

        x = new Node(value, level);
        
        for (int i = 0; i < level; i++) {
            x.next[i] = update[i].next[i];
            update[i].next[i] = x;
        }
    }
}

C++ Code for Skip List

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <cstdlib>
#include <ctime>

struct Node {
    int value;
    Node** next;

    Node(int value, int level) {
        this->value = value;
        this->next = new Node*[level];
    }
};

class SkipList {
private:
    Node* head;
    int maxLevel;

public:
    SkipList() : maxLevel(1) {
        head = new Node(0, 16);
    }

    void insert(int value) {
        Node* update[16];
        Node* x = head;

        for (int i = maxLevel - 1; i >= 0; i--) {
            while (x->next[i] != nullptr && x->next[i]->value < value) {
                x = x->next[i];
            }
            update[i] = x;
        }

        int level = rand() % 16 + 1;

        if (level > maxLevel) {
            for (int i = maxLevel; i < level; i++) {
                update[i] = head;
            }
            maxLevel = level;
        }

        x = new Node(value, level);

        for (int i = 0; i < level; i++) {
            x->next[i] = update[i]->next[i];
            update[i]->next[i] = x;
        }
    }
};

Python Code for Skip List

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import random

class Node:
    def __init__(self, value, level):
        self.value = value
        self.next = [None] * level

class SkipList:
    def __init__(self):
        self.head = Node(0, 16)
        self.max_level = 1

    def insert(self, value):
        update = [None] * self.max_level
        x = self.head

        for i in reversed(range(self.max_level)):
            while x.next[i] and x.next[i].value < value:
                x = x.next[i]
            update[i] = x

        level = random.randint(1, 16)

        if level > self.max_level:
            for i in range(self.max_level, level):
                update.append(self.head)
            self.max_level = level

        x = Node(value, level)

        for i in range(level):
            x.next[i] = update[i].next[i]
            update[i].next[i] = x

In all three implementations, the logic is the same:

  1. Each node contains an array called next to hold the next pointers for each level.
  2. A new node is inserted at appropriate locations at all levels where it appears.
  3. Random levels are generated for each new node to decide how high the node will appear in the Skip List.

Skip Lists are useful because they provide a balance between efficiency and simplicity. They are particularly effective when you need a data structure that supports fast insert, delete, and search operations but you want to avoid the complexity of balanced tree structures.