2025年5月31日 00:38:35 星期六

算法:跳跃表的实现

用python实现跳跃表

  1. import random
  2. class SkipList(object):
  3. def __init__(self):
  4. self.level = [None, None, None, None, None]
  5. def insert(self, node):
  6. pre_node = self._find_pre(node)
  7. node.prev = pre_node
  8. will_affect = []
  9. temp_node = pre_node
  10. while 1:
  11. if len(temp_node.level) < len(node.level):
  12. will_affect.append(temp_node)
  13. temp_node = temp_node.prev
  14. else:
  15. will_affect.append(temp_node)
  16. break
  17. for affect_node in will_affect:
  18. for k, p_node in enumerate(affect_node.level):
  19. if p_node is None or p_node.score > node.score:
  20. if k < len(node.level):
  21. # 修改指针
  22. node.level[k] = p_node
  23. affect_node.level[k] = node
  24. def _find_pre(self, node):
  25. pre_node = self
  26. while 1:
  27. for i in range(len(pre_node.level)-1, -1, -1):
  28. p_node = pre_node.level[i]
  29. if p_node is None:
  30. continue
  31. elif p_node.score > node.score:
  32. continue
  33. elif p_node.score <= node.score:
  34. pre_node = p_node
  35. break
  36. else:
  37. return pre_node
  38. def get_range(self, start_score, stop_score):
  39. start_node = self._find_pre(SkipListNode('', start_score))
  40. while 1:
  41. if isinstance(start_node, SkipList):
  42. start_node = start_node.level[0]
  43. break
  44. if isinstance(start_node.prev, SkipList):
  45. break
  46. if start_node.prev.score >= start_score:
  47. start_node = start_node.prev
  48. else:
  49. break
  50. result = []
  51. while 1:
  52. if start_node and start_score <= start_node.score <= stop_score:
  53. result.append(start_node)
  54. start_node = start_node.level[0]
  55. else:
  56. break
  57. return result
  58. class SkipListNode(object):
  59. def __init__(self, key, score):
  60. self.key = key
  61. self.score = score
  62. self.prev = None
  63. self.level = []
  64. for i in range(0, random.randint(1,5)):
  65. self.level.append(None)
  66. if __name__ == '__main__':
  67. # test
  68. skip_list = SkipList()
  69. node = SkipListNode('helloworld1', 1)
  70. skip_list.insert(node)
  71. node = SkipListNode('helloworld31', 3)
  72. skip_list.insert(node)
  73. node = SkipListNode('helloworld2', 2)
  74. skip_list.insert(node)
  75. node = SkipListNode('helloworld32', 3)
  76. skip_list.insert(node)
  77. node = SkipListNode('helloworld33', 3)
  78. skip_list.insert(node)
  79. result = skip_list.get_range(3, 3)
  80. assert len(result) == 3
  81. for node in result:
  82. print(node.key)
  83. print(node.score)
  84. assert node.score == 3
  85. result = skip_list.get_range(1, 2)
  86. assert len(result) == 2
  87. for node in result:
  88. print(node.key)
  89. print(node.score)
  90. assert node.score in [1,2]

Level的随机生成

在跳跃表中,每个节点的level数随机按1-5生成并不是很好,可以引入一个算法。在redis中,每个节点的level有1-32层。层数越大的节点越少。具体上,可以这样实现:

  1. import random
  2. import math
  3. def get_random(size):
  4. # 产生[0-n)的随机数,数越大,则产生的概率越小
  5. return size - int(math.sqrt(random.randint(0, size*size-1))) -1
  6. count = [0]*32
  7. for i in range(1000000):
  8. rnd = get_random(32)
  9. count[rnd] += 1
  10. print(count)
  11. 100W 次结果:
  12. [61411, 59880, 57719, 55929, 53847, 51683, 49576, 47808, 45463, 43657, 41902, 40120, 38288, 36274, 34416, 32375, 30376,28179, 26208, 24222, 22481, 20539, 18502, 16698, 14615, 12859, 10536, 8892, 6803, 4925, 2878, 939]

来自 大脸猫 写于 2017-12-06 17:34 -- 更新于2020-10-19 13:06 -- 0 条评论

0条评论

字体
字号


评论: