skip list
implements with detailed comments
This commit is contained in:
parent
947b490d26
commit
2fdca2e60c
118
python/17_skiplist/skip_list_comments.py
Normal file
118
python/17_skiplist/skip_list_comments.py
Normal file
@ -0,0 +1,118 @@
|
||||
import random
|
||||
|
||||
|
||||
class SkipListNode(object):
|
||||
def __init__(self, val, high=1):
|
||||
# 节点存储的值
|
||||
self.data = val
|
||||
# 节点对应索引层的深度
|
||||
self.deeps = [None] * high
|
||||
|
||||
|
||||
class SkipList(object):
|
||||
"""
|
||||
An implementation of skip list.
|
||||
The list stores positive integers without duplicates.
|
||||
跳表的一种实现方法。
|
||||
跳表中储存的是正整数,并且储存的是不重复的。
|
||||
Author: Ben
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
# 索引层的最大深度
|
||||
self.__MAX_LEVEL = 16
|
||||
# 跳表的高度
|
||||
self._high = 1
|
||||
# 每一索引层的首节点, 默认值为None
|
||||
self._head = SkipListNode(None, self.__MAX_LEVEL)
|
||||
|
||||
def find(self, val):
|
||||
cur = self._head
|
||||
# 从索引的顶层, 逐层定位要查找的值
|
||||
# 索引层上下是对应的, 下层的起点是上一个索引层中小于插入值的最大值对应的节点
|
||||
for i in range(self._high - 1, -1, -1):
|
||||
# 同一索引层内, 查找小于插入值的最大值对应的节点
|
||||
while cur.deeps[i] and cur.deeps[i].data < val:
|
||||
cur = cur.deeps[i]
|
||||
|
||||
if cur.deeps[0] and cur.deeps[0].data == val:
|
||||
return cur.deeps[0]
|
||||
return None
|
||||
|
||||
def insert(self, val):
|
||||
'''
|
||||
新增时, 通过随机函数获取要更新的索引层数,
|
||||
要对低于给定高度的索引层添加新结点的指针
|
||||
'''
|
||||
high = self.randomLevel()
|
||||
if self._high < high:
|
||||
self._high = high
|
||||
# 申请新结点
|
||||
newNode = SkipListNode(val, high)
|
||||
# cache用来缓存对应索引层中小于插入值的最大节点
|
||||
cache = [self._head] * high
|
||||
cur = self._head
|
||||
|
||||
# 在低于随机高度的每一个索引层寻找小于插入值的节点
|
||||
for i in range(high - 1, -1, -1):
|
||||
# 每个索引层内寻找小于带插入值的节点
|
||||
# ! 索引层上下是对应的, 下层的起点是上一个索引层中小于插入值的最大值对应的节点
|
||||
while cur.deeps[i] and cur.deeps[i].data < val:
|
||||
cur = cur.deeps[i]
|
||||
cache[i] = cur
|
||||
|
||||
# 在小于高度的每个索引层中插入新结点
|
||||
for i in range(high):
|
||||
# new.next = prev.next \ prev.next = new.next
|
||||
newNode.deeps[i] = cache[i].deeps[i]
|
||||
cache[i].deeps[i] = newNode
|
||||
|
||||
def delete(self, val):
|
||||
'''
|
||||
删除时, 要将每个索引层中对应的节点都删掉
|
||||
'''
|
||||
# cache用来缓存对应索引层中小于插入值的最大节点
|
||||
cache = [None] * self._high
|
||||
cur = self._head
|
||||
# 缓存每一个索引层定位小于插入值的节点
|
||||
for i in range(self._high - 1, -1, -1):
|
||||
while cur.deeps[i] and cur.deeps[i].data < val:
|
||||
cur = cur.deeps[i]
|
||||
cache[i] = cur
|
||||
# 如果给定的值存在, 更新索引层中对应的节点
|
||||
if cur.deeps[0] and cur.deeps[0].data == val:
|
||||
for i in range(self._high):
|
||||
if cache[i].deeps[i] and cache[i].deeps[i].data == val:
|
||||
cache[i].deeps[i] = cache[i].deeps[i].deeps[i]
|
||||
|
||||
def randomLevel(self, p=0.25):
|
||||
'''
|
||||
#define ZSKIPLIST_P 0.25 /* Skiplist P = 1/4 */
|
||||
https://github.com/antirez/redis/blob/unstable/src/t_zset.c
|
||||
'''
|
||||
high = 1
|
||||
for _ in range(self.__MAX_LEVEL - 1):
|
||||
if random.random() < p:
|
||||
high += 1
|
||||
return high
|
||||
|
||||
def __repr__(self):
|
||||
vals = []
|
||||
p = self._head
|
||||
while p.deeps[0]:
|
||||
vals.append(str(p.deeps[0].data))
|
||||
p = p.deeps[0]
|
||||
return '->'.join(vals)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sl = SkipList()
|
||||
for i in range(100):
|
||||
sl.insert(i)
|
||||
print(sl)
|
||||
p = sl.find(7)
|
||||
print(p.data)
|
||||
sl.delete(37)
|
||||
print(sl)
|
||||
sl.delete(37.5)
|
||||
print(sl)
|
Loading…
Reference in New Issue
Block a user