circular_list.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. # circular doubly linked list
  2. #
  3. # by Greg Hazel
  4. import random
  5. class Link(object):
  6. __slots__ = ['prev', 'data', 'next']
  7. def __init__(self, data):
  8. self.prev = self
  9. self.data = data
  10. self.next = self
  11. def __str__(self):
  12. p = id(self.prev)
  13. n = id(self.next)
  14. return 'link:(%s, (%s, %s), %s)' % (p, id(self), self.data, n)
  15. class CircularList(object):
  16. def __init__(self):
  17. self.iter = None
  18. self.link_refs = {} # data: link
  19. def prepend(self, data):
  20. link = Link(data)
  21. assert data not in self.link_refs
  22. self.link_refs[data] = link
  23. if not self.iter:
  24. self.iter = link
  25. else:
  26. self._insert_before(self.iter, link)
  27. def append(self, data):
  28. link = Link(data)
  29. assert data not in self.link_refs
  30. self.link_refs[data] = link
  31. if not self.iter:
  32. self.iter = link
  33. else:
  34. self._insert_after(self.iter, link)
  35. def remove(self, data):
  36. link = self.link_refs.pop(data)
  37. if len(self.link_refs) == 0:
  38. self.iter = None
  39. return
  40. prev = link.prev
  41. next = link.next
  42. assert next is not None and prev is not None
  43. prev.next = next
  44. next.prev = prev
  45. if link == self.iter:
  46. self.iter = next
  47. ## stuff I consider to be link-related
  48. ########
  49. def _double_link(self, link1, link2):
  50. # was a single item loop, move to a double
  51. assert link1.prev == link1 and link1.next == link1
  52. link1.prev = link2
  53. link1.next = link2
  54. link2.next = link1
  55. link2.prev = link1
  56. def _insert_after(self, link1, link2):
  57. assert link1 != link2
  58. if link1.next == link1:
  59. self._double_link(link1, link2)
  60. else:
  61. link2.next = link1.next
  62. link2.prev = link1
  63. link1.next.prev = link2
  64. link1.next = link2
  65. def _insert_before(self, link1, link2):
  66. assert link1 != link2
  67. if link1.prev == link1:
  68. self._double_link(link1, link2)
  69. else:
  70. link2.prev = link1.prev
  71. link2.next = link1
  72. link1.prev.next = link2
  73. link1.prev = link2
  74. ########
  75. def iterator(self):
  76. for i in iter(self):
  77. yield i
  78. def __iter__(self):
  79. if not self.iter:
  80. return
  81. while True:
  82. yield self.iter.data
  83. # someone could remove an item during iteration
  84. if not self.iter:
  85. return
  86. self.iter = self.iter.next
  87. def __len__(self):
  88. return len(self.link_refs)
  89. def __str__(self):
  90. n = len(self.link_refs)
  91. a = []
  92. # don't interrupt iteration for a print
  93. first = self.iter
  94. next = first
  95. while next:
  96. a.append(str(next))
  97. next = next.next
  98. if next.data == first.data:
  99. break
  100. items = '\n'.join(a)
  101. return "iter: %s \n[\n%s\n]" % (self.iter, items)
  102. if __name__ == '__main__':
  103. import time
  104. length = 80000
  105. class ltype(list):
  106. def prepend(self, i):
  107. self.insert(0, i)
  108. from BTL.Lists import QList
  109. class qtype(QList):
  110. def prepend(self, i):
  111. self.append(i)
  112. def iterator(self):
  113. if len(self) == 0:
  114. return
  115. while True:
  116. yield self[0]
  117. if len(self) == 0:
  118. return
  119. self.append(self.popleft())
  120. #CircularList = ltype
  121. #CircularList = qtype
  122. print CircularList
  123. s = time.clock()
  124. l = CircularList()
  125. for i in xrange(length):
  126. l.append(i)
  127. #print l
  128. print 'append ', time.clock() - s
  129. s = time.clock()
  130. l = CircularList()
  131. for i in xrange(length):
  132. l.prepend(i)
  133. #print l
  134. print 'prepend', time.clock() - s
  135. s = time.clock()
  136. l = CircularList()
  137. for i in xrange(length):
  138. if i % 2 == 0:
  139. l.prepend(i)
  140. else:
  141. l.append(i)
  142. #print l
  143. print 'sort ', time.clock() - s
  144. #fair = {}
  145. s = time.clock()
  146. l = CircularList()
  147. it = l.iterator()
  148. for i in xrange(length):
  149. l.prepend(i)
  150. #fair[i] = 0
  151. x = it.next()
  152. #print x, i
  153. #fair[x] += 1
  154. #assert x == i, '%s %s' % (x, i)
  155. #print l
  156. print 'iter ', time.clock() - s
  157. #for k in fair:
  158. # print k, fair[k]
  159. l = CircularList()
  160. print l
  161. l.prepend(0)
  162. print l
  163. l.prepend(1)
  164. print l
  165. l.remove(1)
  166. print l
  167. l.remove(0)
  168. print l