代表性面试主题

如何实现 Skip List,并解释它为何期望 O(log N)?

编程题困难
OfferCC 编辑团队发布 更新

题干

请实现支持搜索、插入、删除和范围遍历的 Skip List。说明随机层高如何替代平衡树、最坏情况是什么,以及如何处理重复键和并发读写。

1. 题目

你需要一个有序字典,支持按键搜索、插入、删除和范围扫描。数据量会动态增长,面试官要求平均操作接近 O(log N),但不要求实现 AVL 或红黑树。请设计 Skip List 并分析随机性、边界和内存布局。

2. 约束与澄清

  • 明确键是否唯一;若重复,定义覆盖、计数或稳定顺序。
  • 设定最大层数和每层晋升概率 p,通常从底层链表开始向上建立索引。
  • 搜索、插入和删除需要维护每一层的前驱节点;范围遍历只需沿底层链表前进。
  • 先讨论单线程结构;若要并发,需要额外的锁、版本或无锁算法证明。

3. 核心思路

每个节点拥有高度随机的 forward 指针数组。搜索从最高层头节点开始:若下一个键仍小于目标,就沿当前层前进;否则下降一层。插入先记录每层前驱,再随机生成新高度并逐层接入。删除同样使用前驱数组断开指针。随机层高使高层节点稀疏,期望总指针数为 O(N),搜索、插入和删除的期望时间为 O(log N)。

4. 参考实现

text
randomLevel(rng, p, maxLevel):
  level = 1
  while level < maxLevel and rng.uniform01() < p:
    level += 1
  return level

findPredecessors(key):
  update = array(maxLevel)
  node = head
  for level from maxLevel - 1 down to 0:
    while node.forward[level] != nil and node.forward[level].key < key:
      node = node.forward[level]
    update[level] = node
  return update

insert(key, value):
  update = findPredecessors(key)
  if update[0].forward[0].key == key:
    update[0].forward[0].value = value
    return
  node = Node(key, value, randomLevel(rng, p, maxLevel))
  for level in 0 .. node.height - 1:
    node.forward[level] = update[level].forward[level]
    update[level].forward[level] = node

实现中必须先检查 nil 再读取键,并保证新节点的高度不超过 maxLevel。删除时把所有指向目标节点的层级一次性接到后继节点;最高层为空后可降低当前有效层数,但不必移动节点。

5. 复杂度与最坏情况

当晋升概率固定且随机源独立时,层数和路径长度的期望为对数级,空间期望为 O(N)。随机性失效或敌手能预测层高时,结构可能退化成单链表,操作变为 O(N)。可使用高质量随机源、限制最大高度、定期重建或采用确定性平衡树来处理对抗性工作负载。

6. 验证与并发取舍

  • 用有序、重复、空结构和极端键测试搜索、更新、删除及范围遍历。
  • 统计不同 N 下的高度分布、平均路径长度和指针数量,检查是否符合预期。
  • 做随机操作序列,与标准有序映射对拍,验证内容和顺序一致。
  • 并发版本要说明读写锁粒度、删除标记、内存回收和 ABA 风险;不能只把指针写入包在一个锁里就宣称无锁安全。

7. 常见误区

  • 只写搜索,不维护每层前驱,导致插入或删除退化为重新扫描。
  • 忽略重复键策略,插入后范围遍历顺序不稳定。
  • 把期望 O(log N) 当作最坏保证,未讨论随机源和对抗性输入。
  • 用固定高度数组浪费内存,或允许高度无界导致数组越界。

8. 面试评分点

能从高层向下搜索

应说明每层前进条件、下降时机,以及为什么底层链表包含全部元素。

能正确维护前驱

应在插入和删除中保存各层 update 数组,处理覆盖、空指针和最高层收缩。

能解释概率复杂度

应给出 O(log N) 期望时间、O(N) 期望空间和退化到 O(N) 的条件。

能识别并发边界

应讨论锁、版本、标记删除、内存回收与 ABA,而不是把单线程代码直接当作并发实现。

公开来源

同类题目

资源

产品对比

每份对比均基于官方资料,并标注复核日期。

查看完整对比

相关面试工具

用 Screenshot 处理算法题

截图题目后,按顺序看约束、解法、代码、边界条件和复杂度。

查看工具