返回

数据结构入门:跳表实现指南

后端

跳表简介

跳表是一种高效的链表数据结构,它通过引入多个层次的指针(称为跳跃指针)来优化搜索和插入操作。这些跳跃指针允许快速跳过链表中的多个元素,从而缩短了查找和插入的时间。跳表在实际应用中非常有用,例如数据库和分布式系统。

LeetCode 1206 题解

LeetCode 1206 题要求我们实现一个跳表数据结构。以下是如何使用 Java 实现此跳表:

import java.util.Random;

class Skiplist {

    private static final double P = 0.5;
    private Node head, tail;
    private int level, size;
    private Random random;

    public Skiplist() {
        head = new Node(Integer.MIN_VALUE, Integer.MAX_VALUE, 0);
        tail = new Node(Integer.MAX_VALUE, Integer.MAX_VALUE, 0);
        for (int i = 0; i < head.nexts.length; i++) {
            head.nexts[i] = tail;
        }
        level = 0;
        size = 0;
        random = new Random();
    }

    public boolean search(int target) {
        Node curr = head;
        for (int i = level - 1; i >= 0; i--) {
            while (curr.nexts[i].val < target) {
                curr = curr.nexts[i];
            }
        }
        curr = curr.nexts[0];
        return curr.val == target;
    }

    public void add(int num) {
        int newLevel = randomLevel();
        level = Math.max(level, newLevel);
        Node newNode = new Node(num, new int[newLevel]);
        for (int i = 0; i < newLevel; i++) {
            newNode.nexts[i] = findNext(i, num);
            findPrev(i, num).nexts[i] = newNode;
        }
        size++;
    }

    public boolean erase(int num) {
        Node curr = head;
        boolean removed = false;
        for (int i = level - 1; i >= 0; i--) {
            while (curr.nexts[i].val < num) {
                curr = curr.nexts[i];
            }
            if (curr.nexts[i].val == num) {
                removed = true;
                curr.nexts[i] = curr.nexts[i].nexts[i];
                if (i == level - 1 && curr.nexts[i] == tail) {
                    level--;
                }
            }
        }
        if (removed) {
            size--;
        }
        return removed;
    }

    private int randomLevel() {
        int lvl = 1;
        while (random.nextDouble() < P && lvl < 32) {
            lvl++;
        }
        return lvl;
    }

    private Node findPrev(int level, int num) {
        Node curr = head;
        while (curr.nexts[level].val < num) {
            curr = curr.nexts[level];
        }
        return curr;
    }

    private Node findNext(int level, int num) {
        Node curr = head;
        while (curr.nexts[level] != null && curr.nexts[level].val <= num) {
            curr = curr.nexts[level];
        }
        return curr.nexts[level];
    }

    private static class Node {
        int val;
        int[] nexts;

        public Node(int val, int maxLevel) {
            this.val = val;
            nexts = new int[maxLevel];
        }

        public Node(int val, int[] nexts) {
            this.val = val;
            this.nexts = nexts;
        }
    }
}

理解关键实现细节

  • 层级结构: 跳表使用多个层次的指针(称为跳跃指针)来实现快速搜索。
  • 随机层级: 新节点的层级数是随机生成的,以达到平均 O(log n) 的时间复杂度。
  • 搜索和插入: 使用跳跃指针进行搜索和插入,可以快速跳过链表中的多个元素。
  • 删除: 删除节点时,需要更新所有受影响的跳跃指针。

总结

跳表是一种强大的数据结构,它结合了链表的简单性和树的快速搜索能力。通过理解跳表的概念和实现细节,你可以提升自己的算法技能,在实际应用中有效解决复杂的数据处理问题。