Skip Lists & Treaps

Skip List ও Treap

Read: ~40 min Advanced 5 practice problems Live code runner

1. Randomisation Replaces Rotations

AVL and Red-Black trees achieve guaranteed O(log n) using rotations + colour bookkeeping. Skip lists and treaps achieve expected O(log n) using random coin flips — no rotations to think about, no colour invariants. The code is shorter and the constant factor is often better.

AVL/RB tree rotation দিয়ে balance ঠিক রাখে। Skip list ও treap এর বদলে randomization ব্যবহার করে — coin toss-এর সাহায্যে balance probabilistically নিশ্চিত হয়। কোড অনেক ছোট, performance বাস্তবে প্রায় একই।

2. Skip List — Linked Lists at Multiple Levels

A skip list is a sorted linked list where each node optionally appears in higher levels. With probability 1/2, each node is also in level 1; with 1/4, in level 2; and so on. Search descends from the top: at each level, walk forward as long as the next value ≤ target. Expected height is O(log n), expected search O(log n).

L2: 3 25 L1: 3 10 25 40 L0: 3 7 10 14 22 25 31 40 Figure 25.1 — Skip list with three levels. Search for 22: start L2, advance to 3 (next is 25 > 22, drop); L1, advance 3→10 (next is 25 > 22, drop); L0 walk 10→14→22. Expected O(log n) hops.
skip_list.cpp
#include <bits/stdc++.h>
using namespace std;

struct SkipList {
    struct Node { int v; vector<Node*> nxt; };
    int maxLevel;
    Node* head;
    mt19937 rng;

    SkipList(int ml = 16) : maxLevel(ml), rng(42) {
        head = new Node{INT_MIN, vector<Node*>(ml, nullptr)};
    }

    int randomLevel() {
        int lvl = 1;
        while ((rng() & 1) && lvl < maxLevel) lvl++;
        return lvl;
    }
    void insert(int v) {
        vector<Node*> upd(maxLevel, head);
        Node* cur = head;
        for (int i = maxLevel - 1; i >= 0; i--) {
            while (cur->nxt[i] && cur->nxt[i]->v < v) cur = cur->nxt[i];
            upd[i] = cur;
        }
        int lvl = randomLevel();
        Node* node = new Node{v, vector<Node*>(lvl, nullptr)};
        for (int i = 0; i < lvl; i++) {
            node->nxt[i] = upd[i]->nxt[i];
            upd[i]->nxt[i] = node;
        }
    }
    bool contains(int v) {
        Node* cur = head;
        for (int i = maxLevel - 1; i >= 0; i--)
            while (cur->nxt[i] && cur->nxt[i]->v < v) cur = cur->nxt[i];
        return cur->nxt[0] && cur->nxt[0]->v == v;
    }
};

int main() {
    SkipList sl;
    for (int x : {3, 7, 10, 14, 22, 25, 31, 40}) sl.insert(x);
    cout << sl.contains(22) << " " << sl.contains(9);
}

3. Treap — BST by Key, Heap by Priority

A treap assigns each inserted key a random priority. The structure is a BST on keys and a heap on priorities. Random priorities ⇒ random tree shape ⇒ expected height O(log n). Insertion is BST-insert, then rotations to restore the heap property — but you can equivalently implement it via split / merge, which is cleaner.

Split / Merge primitives split(t, key) → (lo, hi): lo contains all nodes with key < given, hi the rest. merge(lo, hi): combine assuming all keys in lo < all keys in hi. Insert and erase are 1–2 splits + a merge.
Treap-এ random priority দিয়ে BST-এর shape randomize করা হয় — sorted insertion-এও tree degenerate হয় না। split/merge দিয়ে implementation কম রিস্কি।

4. Implicit Treap — Treat Position as Key

If we use the in-order position (rather than a value) as the implicit key, treap becomes a powerful sequence container: insert at position k, erase at position k, range-reverse, range-sum — all in O(log n). This is what powers many hard ICPC problems where you need to simulate sequence edits.

5. Where They Live in the Real World

StructureUsed byWhy
Skip listRedis ZSET, LevelDB MemTableEasy concurrent insert; no rotations
TreapICPC contest librariesShort code, split/merge for sequences
Implicit treapCodeforces hard problemsRange insert / erase / reverse in O(log n)

6. Practice Problems

  1. Compute the expected height of a skip list of n nodes when each level is taken with probability ½.
    Expected height কীভাবে log₂ n হয়?
    ✨ Show Answer (উত্তর দেখুন)

    Answer: probability that a node reaches level h is (½)ʰ. Expected number of nodes at level h is n / 2ʰ. The maximum non-empty level satisfies n/2ʰ ≥ 1, so h ≤ log₂ n. Tail bounds make actual height O(log n) w.h.p.

  2. Given priorities P = [50, 30, 80, 10, 20] for keys [4, 2, 8, 1, 5] inserted in this order, draw the resulting treap.
    দেওয়া (key, priority) pair-এর treap আঁকুন।
    ✨ Show Answer (উত্তর দেখুন)

    Answer: root is the priority-max = 80 (key 8). Its left subtree contains keys < 8 with their own priority-max as root: P among {4, 2, 1, 5} largest is 50 (key 4). Recurse → final tree: root 8(80) → left 4(50) → (left 2(30) → (left 1(10), right —), right 5(20)).

  3. Sketch split(treap, key) in pseudocode using recursion.
    Treap split-এর recursion।
    ✨ Show Answer (উত্তর দেখুন)
    split(t, key):
      if t is null: return (null, null)
      if t.key < key:
        (lo, hi) = split(t.right, key)
        t.right = lo
        return (t, hi)
      else:
        (lo, hi) = split(t.left, key)
        t.left = hi
        return (lo, t)
  4. Implicit treap — kth element retrieval. Sketch the descent.
    Implicit treap-এ kth element।
    ✨ Show Answer (উত্তর দেখুন)

    Sketch: store size at each node. Descend from root: if k < size(left) → go left; else if k == size(left) → return root; else → go right with k = k − size(left) − 1. O(log n) expected.

  5. Why does Redis pick a skip list for sorted-set, when a Red-Black tree would also give O(log n)?
    Redis Red-Black tree-এর বদলে skip list বেছে নেয় কেন?
    ✨ Show Answer (উত্তর দেখুন)

    Answer: (1) Range queries (ZRANGEBYSCORE) are trivial — walk the bottom-level linked list. (2) Implementation is dramatically simpler — no rotations, no parent pointers, no rebalancing on every write. (3) Cache-friendlier for forward iteration. The constant factor and engineering simplicity matter more than asymptotic differences here.

Summary — Module 25

Randomised structures get rid of rotation bookkeeping. Skip lists put randomness into the number of "express lanes" each node joins; treaps put it into priorities. Both run in expected O(log n). Skip lists power Redis sorted sets; implicit treaps unlock sequence problems unreachable with arrays. Phase 5 complete — graphs await.

Randomization দিয়ে balance — rotation নেই, code ছোট, performance প্রায় AVL-এর সমান। Implicit treap = sequence-এর জন্য সুপার-পাওয়ার।

Next Module → Graph Representations & Traversals — Phase 6 শুরু।