核心API:
__find_pre_node(target)
:找到某个值的前置点,查询时与插入相反,是从上往下走迭代的。insert(data)
:根据插入到前置点之后,随机晋升。晋升时要往前回溯到上一个可向上的节点,向上走并构建上下通道search(target)
:基于__find_pre_node
实现查询节点。remove(target)
:删除节点,当节点有晋升时,要往上递归删除;当要删除的节点为当前层最后一个时,要移除层。__add_level()
/__sub_level(level_head)
:增加/减少层数,要注意node为最后一层时,不可把层数减为负。
一篇讲解: https://mp.weixin.qq.com/s/-1_jchMgIVeUdDhlTQCnnA,原文中的代码实现存在bug,配合下面的python代码理解更方便一些。
基本节点的数据结构:
class Node:
def __init__(self, value):
self.pre = self.next = None
self.down = self.up = None
self.v = value
跳表的python实现:
class SkipList:
def __init__(self, promote_rate=0.5):
self.max_level = 0
self.head, self.tail = Node(-float('inf')), Node(float('inf'))
self.promote_rate = promote_rate # 随机晋升概率
self.head.next, self.tail.pre = self.tail, self.head
def __find_pre_node(self, target: Any):
cur = self.head
while True:
while cur.next.v != float('inf') and cur.next.v <= target:
cur = cur.next
if cur.down is None: # 到最底层
break
cur = cur.down
return cur
def insert(self, data: Any):
import random
pre_node = self.__find_pre_node(data)
new_node = Node(data)
self.__append_node(pre_node, new_node)
current_level = 0
while random.random() > self.promote_rate: # 随机决定晋升
if current_level == self.max_level:
self.__add_level()
while pre_node.up is None: # 找到通向上一层的前置节点
pre_node = pre_node.pre
pre_node = pre_node.up # 向上走
upper_new_node = Node(data) # 晋升
self.__append_node(pre_node, upper_new_node) # 上一层右插入
upper_new_node.down, new_node.up = new_node, upper_new_node # 构建上下层关系
new_node = upper_new_node
current_level += 1
def search(self, target: Any):
pre = self.__find_pre_node(target)
return pre if pre.v == target else None
def remove(self, target: Any) -> Node:
removed_node = self.search(target)
if removed_node is not None:
current_level = 0
cur = removed_node
while cur is not None:
self.__remove_node(cur) # 删除节点
q1 = cur.pre.v == -float('inf') and cur.next.v == float('inf') # 如果当前层空了
if current_level != 0 and q1: # 非最下层
self.__sub_level(cur.pre)
else:
current_level += 1
cur = cur.up # 尝试向上移动并移除所有层的相关内容
return removed_node
def __add_level(self):
new_head, new_tail = Node(-float('inf')), Node(float('inf'))
new_head.next, new_tail.pre = new_tail, new_tail
new_head.down, self.head.up = self.head, new_head
new_tail.down, self.tail.up = self.tail, new_tail
self.head, self.tail = new_head, new_tail
self.max_level += 1
def __sub_level(self, level_head: Node): # 删除node所在的层
level_tail = level_head.next
if level_head.up is None: # 是最高层
level_head.down.up = level_tail.down.up = None
self.head, self.tail = level_head.down, level_tail.down # 原文的bug点在于此
else:
level_head.up.down, level_head.down.up = level_head.down, level_head.up
level_tail.up.down, level_tail.down.up = level_tail.down, level_tail.up
self.max_level -= 1
def __append_node(self, pre_node: Node, new_node: Node): # 双向链表左右方向的插入
new_node.pre, new_node.next = pre_node, pre_node.next
pre_node.next.pre = pre_node.next = new_node
def __remove_node(self, node: Node): # 双向链表左右方向的移除
node.next.pre, node.pre.next = node.pre, node.next # 删除节点