skiplistlist.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. """A skiplist implementation of the List interface
  2. W. Pugh. Skip Lists: A probabilistic alternative to balanced trees.
  3. In Communications of the ACM, 33(6), pp. 668-676, June 1990.
  4. W. Pugh. A skip list cookbook. CS-TR-2286.1, University of Maryland,
  5. College Park, 1990.
  6. """
  7. import random
  8. import numpy
  9. from utils import new_array
  10. from base import BaseList
  11. import pprint
  12. class SkiplistList(BaseList):
  13. class Node(object):
  14. """A node in a skip list"""
  15. def __init__(self, x, h):
  16. self.x = x
  17. self.next = new_array(h+1)
  18. self.length = numpy.ones(h+1, dtype=int)
  19. def height(self):
  20. return len(self.next) - 1
  21. def _new_node(self, x, h):
  22. return SkiplistList.Node(x, h)
  23. def __init__(self, iterable=[]):
  24. self._initialize()
  25. self.add_all(iterable)
  26. def _initialize(self):
  27. self.h = 0
  28. self.n = 0
  29. self.sentinel = self._new_node(None, 32)
  30. self.stack = new_array(self.sentinel.height()+1)
  31. def find_pred(self, i):
  32. u = self.sentinel
  33. r = self.h
  34. j = -1
  35. while r >= 0:
  36. while u.next[r] is not None and j + u.length[r] < i:
  37. j += u.length[r]
  38. u = u.next[r] # go right in list r
  39. r -= 1 # go down into list r-1
  40. return u
  41. def get(self, i):
  42. if i < 0 or i > self.n-1: raise IndexError()
  43. return self.find_pred(i).next[0].x
  44. def set(self, i, x):
  45. if i < 0 or i > self.n-1: raise IndexError()
  46. u = self.find_pred(i).next[0]
  47. y = u.x
  48. u.x = x
  49. return y
  50. def _add(self, i, w):
  51. u = self.sentinel
  52. k = w.height()
  53. r = self.h
  54. j = -1
  55. while r >= 0:
  56. while u.next[r] is not None and j+u.length[r] < i:
  57. j += u.length[r]
  58. u = u.next[r]
  59. u.length[r] += 1
  60. if r <= k:
  61. w.next[r] = u.next[r]
  62. u.next[r] = w
  63. w.length[r] = u.length[r] - (i-j)
  64. u.length[r] = i - j
  65. r -= 1
  66. self.n += 1
  67. return u
  68. def add(self, i, x):
  69. if i < 0 or i > self.n: raise IndexError()
  70. w = self._new_node(x, self.pick_height())
  71. if w.height() > self.h:
  72. self.h = w.height()
  73. self._add(i, w)
  74. def remove(self, i):
  75. if i < 0 or i > self.n-1: raise IndexError()
  76. u = self.sentinel
  77. r = self.h
  78. j = -1
  79. while r >= 0:
  80. while u.next[r] is not None and j + u.length[r] < i:
  81. j += u.length[r]
  82. u = u.next[r]
  83. u.length[r] -= 1
  84. if j + u.length[r] + 1 == i and u.next[r] is not None:
  85. x = u.next[r].x
  86. u.length[r] += u.next[r].length[r]
  87. u.next[r] = u.next[r].next[r]
  88. if u == self.sentinel and u.next[r] is None:
  89. self.h -= 1
  90. r -= 1
  91. self.n -= 1
  92. return x
  93. def __iter__(self):
  94. u = self.sentinel.next[0]
  95. while u is not None:
  96. yield u.x
  97. u = u.next[0]
  98. def pick_height(self):
  99. z = random.getrandbits(32)
  100. k = 0
  101. while z & 1:
  102. k += 1
  103. z = z // 2
  104. return k
  105. def truncar(self, i):
  106. u = self.sentinel
  107. r = self.h
  108. j = -1
  109. h2 = None
  110. h1 = None
  111. while r >= 0:
  112. # Percorre para direita ate achar o proximo no nulo ou no depois do indice de truncar
  113. while u.next[r] != None and j + u.length[r] < i:
  114. if h1 == None:
  115. h1 = r
  116. j += u.length[r]
  117. u = u.next[r]
  118. # Cai nesse caso, apenas se houver um no depois do indice de truncar
  119. if u.next[r] != None:
  120. if h2 == None:
  121. h2 = r
  122. w = self._new_node(None, h2)
  123. self._add(i, w)
  124. u.next[r] = None
  125. u.length[r] = 1
  126. r = r - 1
  127. if h1 == None:
  128. h1 = 0
  129. # Cria skiplistlist de retorno
  130. new_skipll = SkiplistList()
  131. new_skipll.sentinel = w
  132. new_skipll.h = h2
  133. new_skipll.n = self.n - i
  134. # Atualiza a altura e numero de elementos da lista truncada
  135. self.h = h1
  136. self.n = i
  137. return new_skipll