123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162 |
- """A skiplist implementation of the List interface
- W. Pugh. Skip Lists: A probabilistic alternative to balanced trees.
- In Communications of the ACM, 33(6), pp. 668-676, June 1990.
- W. Pugh. A skip list cookbook. CS-TR-2286.1, University of Maryland,
- College Park, 1990.
- """
- import random
- import numpy
- from utils import new_array
- from base import BaseList
- import pprint
-
- class SkiplistList(BaseList):
- class Node(object):
- """A node in a skip list"""
- def __init__(self, x, h):
- self.x = x
- self.next = new_array(h+1)
- self.length = numpy.ones(h+1, dtype=int)
- def height(self):
- return len(self.next) - 1
- def _new_node(self, x, h):
- return SkiplistList.Node(x, h)
-
- def __init__(self, iterable=[]):
- self._initialize()
- self.add_all(iterable)
-
- def _initialize(self):
- self.h = 0
- self.n = 0
- self.sentinel = self._new_node(None, 32)
- self.stack = new_array(self.sentinel.height()+1)
-
- def find_pred(self, i):
- u = self.sentinel
- r = self.h
- j = -1
- while r >= 0:
- while u.next[r] is not None and j + u.length[r] < i:
- j += u.length[r]
- u = u.next[r] # go right in list r
- r -= 1 # go down into list r-1
- return u
- def get(self, i):
- if i < 0 or i > self.n-1: raise IndexError()
- return self.find_pred(i).next[0].x
- def set(self, i, x):
- if i < 0 or i > self.n-1: raise IndexError()
- u = self.find_pred(i).next[0]
- y = u.x
- u.x = x
- return y
-
- def _add(self, i, w):
- u = self.sentinel
- k = w.height()
- r = self.h
- j = -1
- while r >= 0:
- while u.next[r] is not None and j+u.length[r] < i:
- j += u.length[r]
- u = u.next[r]
- u.length[r] += 1
- if r <= k:
- w.next[r] = u.next[r]
- u.next[r] = w
- w.length[r] = u.length[r] - (i-j)
- u.length[r] = i - j
- r -= 1
- self.n += 1
- return u
-
- def add(self, i, x):
- if i < 0 or i > self.n: raise IndexError()
- w = self._new_node(x, self.pick_height())
- if w.height() > self.h:
- self.h = w.height()
- self._add(i, w)
-
- def remove(self, i):
- if i < 0 or i > self.n-1: raise IndexError()
- u = self.sentinel
- r = self.h
- j = -1
- while r >= 0:
- while u.next[r] is not None and j + u.length[r] < i:
- j += u.length[r]
- u = u.next[r]
- u.length[r] -= 1
- if j + u.length[r] + 1 == i and u.next[r] is not None:
- x = u.next[r].x
- u.length[r] += u.next[r].length[r]
- u.next[r] = u.next[r].next[r]
- if u == self.sentinel and u.next[r] is None:
- self.h -= 1
- r -= 1
- self.n -= 1
- return x
- def __iter__(self):
- u = self.sentinel.next[0]
- while u is not None:
- yield u.x
- u = u.next[0]
- def pick_height(self):
- z = random.getrandbits(32)
- k = 0
- while z & 1:
- k += 1
- z = z // 2
- return k
- def truncar(self, i):
- u = self.sentinel
- r = self.h
- j = -1
- h2 = None
- h1 = None
- while r >= 0:
- # Percorre para direita ate achar o proximo no nulo ou no depois do indice de truncar
- while u.next[r] != None and j + u.length[r] < i:
- if h1 == None:
- h1 = r
- j += u.length[r]
- u = u.next[r]
- # Cai nesse caso, apenas se houver um no depois do indice de truncar
- if u.next[r] != None:
- if h2 == None:
- h2 = r
- w = self._new_node(None, h2)
- self._add(i, w)
- u.next[r] = None
- u.length[r] = 1
- r = r - 1
- if h1 == None:
- h1 = 0
-
- # Cria skiplistlist de retorno
- new_skipll = SkiplistList()
- new_skipll.sentinel = w
- new_skipll.h = h2
- new_skipll.n = self.n - i
- # Atualiza a altura e numero de elementos da lista truncada
- self.h = h1
- self.n = i
- return new_skipll
|