4 # Purpose: treemixin provides top level functions for binary trees
6 # Copyright (c) 2010-2013 by Manfred Moitzi
9 from __future__
import absolute_import
11 from .walker
import Walker
12 from .treeslice
import TreeSlice
14 class TreeMixin(object):
16 Abstract-Base-Class for the pure Python Trees: BinaryTree, AVLTree and RBTree
17 Mixin-Class for the Cython based Trees: FastBinaryTree, FastAVLTree, FastRBTree
22 T has to implement following properties
23 ---------------------------------------
25 count -- get node count
27 T has to implement following methods
28 ------------------------------------
31 get a tree walker object, provides methods to traverse the tree see walker.py
34 insert(key, value) <==> T[key] = value, insert key into T
37 remove(key) <==> del T[key], remove key from T
40 T.clear() -> None. Remove all items from T.
45 * __contains__(k) -> True if T has a key k, else False, O(log(n))
46 * __delitem__(y) <==> del T[y], del T[s:e], O(log(n))
47 * __getitem__(y) <==> T[y], T[s:e], O(log(n))
48 * __iter__() <==> iter(T)
49 * __len__() <==> len(T), O(1)
50 * __max__() <==> max(T), get max item (k,v) of T, O(log(n))
51 * __min__() <==> min(T), get min item (k,v) of T, O(log(n))
52 * __and__(other) <==> T & other, intersection
53 * __or__(other) <==> T | other, union
54 * __sub__(other) <==> T - other, difference
55 * __xor__(other) <==> T ^ other, symmetric_difference
56 * __repr__() <==> repr(T)
57 * __setitem__(k, v) <==> T[k] = v, O(log(n))
58 * clear() -> None, Remove all items from T, , O(n)
59 * copy() -> a shallow copy of T, O(n*log(n))
60 * discard(k) -> None, remove k from T, if k is present, O(log(n))
61 * get(k[,d]) -> T[k] if k in T, else d, O(log(n))
62 * is_empty() -> True if len(T) == 0, O(1)
63 * items([reverse]) -> generator for (k, v) items of T, O(n)
64 * keys([reverse]) -> generator for keys of T, O(n)
65 * values([reverse]) -> generator for values of T, O(n)
66 * pop(k[,d]) -> v, remove specified key and return the corresponding value, O(log(n))
67 * popitem() -> (k, v), remove and return some (key, value) pair as a 2-tuple, O(log(n))
68 * setdefault(k[,d]) -> T.get(k, d), also set T[k]=d if k not in T, O(log(n))
69 * update(E) -> None. Update T from dict/iterable E, O(E*log(n))
70 * foreach(f, [order]) -> visit all nodes of tree and call f(k, v) for each node, O(n)
74 * itemslice(s, e) -> generator for (k, v) items of T for s <= key < e, O(n)
75 * keyslice(s, e) -> generator for keys of T for s <= key < e, O(n)
76 * valueslice(s, e) -> generator for values of T for s <= key < e, O(n)
77 * T[s:e] -> TreeSlice object, with keys in range s <= key < e, O(n)
78 * del T[s:e] -> remove items by key slicing, for s <= key < e, O(n)
80 if 's' is None or T[:e] TreeSlice/iterator starts with value of min_key()
81 if 'e' is None or T[s:] TreeSlice/iterator ends with value of max_key()
82 T[:] is a TreeSlice which represents the whole tree.
84 TreeSlice is a tree wrapper with range check, and contains no references
85 to objects, deleting objects in the associated tree also deletes the object
88 * TreeSlice[k] -> get value for key k, raises KeyError if k not exists in range s:e
89 * TreeSlice[s1:e1] -> TreeSlice object, with keys in range s1 <= key < e1
91 * new lower bound is max(s, s1)
92 * new upper bound is min(e, e1)
96 * items() -> generator for (k, v) items of T, O(n)
97 * keys() -> generator for keys of T, O(n)
98 * values() -> generator for values of T, O(n)
99 * __iter__ <==> keys()
100 * __repr__ <==> repr(T)
101 * __contains__(key)-> True if TreeSlice has a key k, else False, O(log(n))
105 * prev_item(key) -> get (k, v) pair, where k is predecessor to key, O(log(n))
106 * prev_key(key) -> k, get the predecessor of key, O(log(n))
107 * succ_item(key) -> get (k,v) pair as a 2-tuple, where k is successor to key, O(log(n))
108 * succ_key(key) -> k, get the successor of key, O(log(n))
109 * floor_item(key) -> get (k, v) pair, where k is the greatest key less than or equal to key, O(log(n))
110 * floor_key(key) -> k, get the greatest key less than or equal to key, O(log(n))
111 * ceiling_item(key) -> get (k, v) pair, where k is the smallest key greater than or equal to key, O(log(n))
112 * ceiling_key(key) -> k, get the smallest key greater than or equal to key, O(log(n))
116 * max_item() -> get largest (key, value) pair of T, O(log(n))
117 * max_key() -> get largest key of T, O(log(n))
118 * min_item() -> get smallest (key, value) pair of T, O(log(n))
119 * min_key() -> get smallest key of T, O(log(n))
120 * pop_min() -> (k, v), remove item with minimum key, O(log(n))
121 * pop_max() -> (k, v), remove item with maximum key, O(log(n))
122 * nlargest(i[,pop]) -> get list of i largest items (k, v), O(i*log(n))
123 * nsmallest(i[,pop]) -> get list of i smallest items (k, v), O(i*log(n))
125 Set methods (using frozenset)
127 * intersection(t1, t2, ...) -> Tree with keys *common* to all trees
128 * union(t1, t2, ...) -> Tree with keys from *either* trees
129 * difference(t1, t2, ...) -> Tree with keys in T but not any of t1, t2, ...
130 * symmetric_difference(t1) -> Tree with keys in either T and t1 but not both
131 * issubset(S) -> True if every element in T is in S
132 * issuperset(S) -> True if every element in S is in T
133 * isdisjoint(S) -> True if T has a null intersection with S
137 * fromkeys(S[,v]) -> New tree with keys from S and values equal to v.
140 def get_walker(self
):
144 """ x.__repr__(...) <==> repr(x) """
145 tpl
= "%s({%s})" % (self
.__class
__.__name
__, '%s')
146 return tpl
% ", ".join( ("%r: %r" % item
for item
in self
.items()) )
149 """ T.copy() -> get a shallow copy of T. """
150 tree
= self
.__class
__()
151 self
.foreach(tree
.insert
, order
=-1)
155 def __contains__(self
, key
):
156 """ k in T -> True if T has a key k, else False """
164 """ x.__len__() <==> len(x) """
168 """ x.__min__() <==> min(x) """
169 return self
.min_item()
172 """ x.__max__() <==> max(x) """
173 return self
.max_item()
175 def __and__(self
, other
):
176 """ x.__and__(other) <==> self & other """
177 return self
.intersection(other
)
179 def __or__(self
, other
):
180 """ x.__or__(other) <==> self | other """
181 return self
.union(other
)
183 def __sub__(self
, other
):
184 """ x.__sub__(other) <==> self - other """
185 return self
.difference(other
)
187 def __xor__(self
, other
):
188 """ x.__xor__(other) <==> self ^ other """
189 return self
.symmetric_difference(other
)
191 def discard(self
, key
):
192 """ x.discard(k) -> None, remove k from T, if k is present """
202 """ x.is_empty() -> False if T contains any items else True"""
203 return self
.count
== 0
205 def keys(self
, reverse
=False):
206 """ T.iterkeys([reverse]) -> an iterator over the keys of T, in ascending
207 order if reverse is True, iterate in descending order, reverse defaults
210 return ( item
[0] for item
in self
.items(reverse
) )
213 def __reversed__(self
):
214 return self
.keys(reverse
=True)
216 def values(self
, reverse
=False):
217 """ T.values([reverse]) -> an iterator over the values of T, in ascending order
218 if reverse is True, iterate in descending order, reverse defaults to False
220 return ( item
[1] for item
in self
.items(reverse
) )
222 def items(self
, reverse
=False):
223 """ T.items([reverse]) -> an iterator over the (key, value) items of T,
224 in ascending order if reverse is True, iterate in descending order,
225 reverse defaults to False
230 def default_iterator(node
):
231 direction
= 1 if reverse
else 0
232 other
= 1 - direction
235 if node
.has_child(direction
) and go_down
:
240 if node
.has_child(other
):
244 if node
.stack_is_empty():
249 treewalker
= self
.get_walker()
250 try: # specialized iterators
252 return treewalker
.iter_items_backward()
254 return treewalker
.iter_items_forward()
255 except AttributeError:
256 return default_iterator(treewalker
)
258 def __getitem__(self
, key
):
259 """ x.__getitem__(y) <==> x[y] """
260 if isinstance(key
, slice):
261 return TreeSlice(self
, key
.start
, key
.stop
)
263 return self
.get_value(key
)
265 def __setitem__(self
, key
, value
):
266 """ x.__setitem__(i, y) <==> x[i]=y """
267 if isinstance(key
, slice):
268 raise ValueError('setslice is not supported')
269 self
.insert(key
, value
)
271 def __delitem__(self
, key
):
272 """ x.__delitem__(y) <==> del x[y] """
273 if isinstance(key
, slice):
274 self
.delitems(self
.keyslice(key
.start
, key
.stop
))
278 def delitems(self
, keys
):
279 """ T.delitems(keys) -> remove all items by keys
281 # convert generator to a set, because the content of the
282 # tree will be modified!
283 for key
in frozenset(keys
):
286 def keyslice(self
, startkey
, endkey
):
287 """ T.keyslice(startkey, endkey) -> key iterator:
288 startkey <= key < endkey.
290 return ( item
[0] for item
in self
.itemslice(startkey
, endkey
) )
292 def itemslice(self
, startkey
, endkey
):
293 """ T.itemslice(s, e) -> item iterator: s <= key < e.
295 if s is None: start with min element -> T[:e]
296 if e is None: end with max element -> T[s:]
305 can_go_left
= lambda: node
.has_left() and visit_left
307 # don't visit subtrees without keys in search range
308 can_go_left
= lambda: node
.key
> startkey
and node
.has_left() and visit_left
312 can_go_right
= lambda: node
.has_right()
314 # don't visit subtrees without keys in search range
315 can_go_right
= lambda: node
.key
< endkey
and node
.has_right()
317 if (startkey
, endkey
) == (None, None):
318 key_in_range
= lambda: True
319 elif startkey
is None:
320 key_in_range
= lambda: node
.key
< endkey
322 key_in_range
= lambda: node
.key
>= startkey
324 key_in_range
= lambda: startkey
<= node
.key
< endkey
326 node
= self
.get_walker()
339 if node
.stack_is_empty():
342 # left side is already done
345 def valueslice(self
, startkey
, endkey
):
346 """ T.valueslice(startkey, endkey) -> value iterator:
347 startkey <= key < endkey.
349 return ( item
[1] for item
in self
.itemslice(startkey
, endkey
) )
351 def get_value(self
, key
):
353 while node
is not None:
360 raise KeyError(str(key
))
362 def __getstate__(self
):
363 return dict(self
.items())
365 def __setstate__(self
, state
):
366 # note for myself: this is called like __init__, so don't use clear()
367 # to remove existing data!
372 def setdefault(self
, key
, default
=None):
373 """ T.setdefault(k[,d]) -> T.get(k,d), also set T[k]=d if k not in T """
375 return self
.get_value(key
)
377 self
.insert(key
, default
)
380 def update(self
, *args
):
381 """ T.update(E) -> None. Update T from E : for (k, v) in E: T[k] = v """
384 generator
= items
.items()
385 except AttributeError:
386 generator
= iter(items
)
388 for key
, value
in generator
:
389 self
.insert(key
, value
)
392 def fromkeys(cls
, iterable
, value
=None):
393 """ T.fromkeys(S[,v]) -> New tree with keys from S and values equal to v.
399 tree
.insert(key
, value
)
402 def get(self
, key
, default
=None):
403 """ T.get(k[,d]) -> T[k] if k in T, else d. d defaults to None. """
405 return self
.get_value(key
)
409 def pop(self
, key
, *args
):
410 """ T.pop(k[,d]) -> v, remove specified key and return the corresponding value
411 If key is not found, d is returned if given, otherwise KeyError is raised
414 raise TypeError("pop expected at most 2 arguments, got %d" % (1 + len(args
)))
416 value
= self
.get_value(key
)
426 """ T.popitem() -> (k, v), remove and return some (key, value) pair as a
427 2-tuple; but raise KeyError if T is empty
430 raise KeyError("popitem(): tree is empty")
431 walker
= self
.get_walker()
434 self
.remove(walker
.key
)
437 def foreach(self
, func
, order
=0):
438 """ Visit all tree nodes and process key, value.
440 parm func: function(key, value)
441 param int order: inorder = 0, preorder = -1, postorder = +1
446 func(node
.key
, node
.value
)
453 func(node
.key
, node
.value
)
460 func(node
.key
, node
.value
)
462 node
= self
.get_walker()
466 """ Get item with min key of tree, raises ValueError if tree is empty. """
468 raise ValueError("Tree is empty")
470 while node
.left
is not None:
472 return (node
.key
, node
.value
)
475 """ T.pop_min() -> (k, v), remove item with minimum key, raise ValueError
478 item
= self
.min_item()
483 """ Get min key of tree, raises ValueError if tree is empty. """
484 key
, value
= self
.min_item()
487 def prev_item(self
, key
):
488 """ Get predecessor (k,v) pair of key, raises KeyError if key is min key
489 or key does not exist.
492 raise KeyError("Tree is empty")
493 walker
= self
.get_walker()
494 return walker
.prev_item(key
)
496 def succ_item(self
, key
):
497 """ Get successor (k,v) pair of key, raises KeyError if key is max key
498 or key does not exist.
501 raise KeyError("Tree is empty")
502 walker
= self
.get_walker()
503 return walker
.succ_item(key
)
505 def prev_key(self
, key
):
506 """ Get predecessor to key, raises KeyError if key is min key
507 or key does not exist.
509 key
, value
= self
.prev_item(key
)
512 def succ_key(self
, key
):
513 """ Get successor to key, raises KeyError if key is max key
514 or key does not exist.
516 key
, value
= self
.succ_item(key
)
519 def floor_item(self
, key
):
520 """ Get the element (k,v) pair associated with the greatest key less
521 than or equal to the given key, raises KeyError if there is no such key.
524 raise KeyError("Tree is empty")
525 walker
= self
.get_walker()
526 return walker
.floor_item(key
)
528 def floor_key(self
, key
):
529 """ Get the greatest key less than or equal to the given key, raises
530 KeyError if there is no such key.
532 key
, value
= self
.floor_item(key
)
535 def ceiling_item(self
, key
):
536 """ Get the element (k,v) pair associated with the smallest key greater
537 than or equal to the given key, raises KeyError if there is no such key.
540 raise KeyError("Tree is empty")
541 walker
= self
.get_walker()
542 return walker
.ceiling_item(key
)
544 def ceiling_key(self
, key
):
545 """ Get the smallest key greater than or equal to the given key, raises
546 KeyError if there is no such key.
548 key
, value
= self
.ceiling_item(key
)
552 """ Get item with max key of tree, raises ValueError if tree is empty. """
554 raise ValueError("Tree is empty")
556 while node
.right
is not None:
558 return (node
.key
, node
.value
)
561 """ T.pop_max() -> (k, v), remove item with maximum key, raise ValueError
564 item
= self
.max_item()
569 """ Get max key of tree, raises ValueError if tree is empty. """
570 key
, value
= self
.max_item()
573 def nsmallest(self
, n
, pop
=False):
574 """ T.nsmallest(n) -> get list of n smallest items (k, v).
575 If pop is True, remove items from T.
578 return [self
.pop_min() for _
in range(min(len(self
), n
))]
581 return [ next(items
) for _
in range(min(len(self
), n
)) ]
583 def nlargest(self
, n
, pop
=False):
584 """ T.nlargest(n) -> get list of n largest items (k, v).
585 If pop is True remove items from T.
588 return [self
.pop_max() for _
in range(min(len(self
), n
))]
590 items
= self
.items(reverse
=True)
591 return [ next(items
) for _
in range(min(len(self
), n
)) ]
593 def intersection(self
, *trees
):
594 """ x.intersection(t1, t2, ...) -> Tree, with keys *common* to all trees
596 thiskeys
= frozenset(self
.keys())
597 sets
= _build_sets(trees
)
598 rkeys
= thiskeys
.intersection(*sets
)
599 return self
.__class
__( ((key
, self
.get(key
)) for key
in rkeys
) )
601 def union(self
, *trees
):
602 """ x.union(t1, t2, ...) -> Tree with keys from *either* trees
604 thiskeys
= frozenset(self
.keys())
605 rkeys
= thiskeys
.union(*_build_sets(trees
))
606 return self
.__class
__( ((key
, self
.get(key
)) for key
in rkeys
) )
608 def difference(self
, *trees
):
609 """ x.difference(t1, t2, ...) -> Tree with keys in T but not any of t1,
612 thiskeys
= frozenset(self
.keys())
613 rkeys
= thiskeys
.difference(*_build_sets(trees
))
614 return self
.__class
__( ((key
, self
.get(key
)) for key
in rkeys
) )
616 def symmetric_difference(self
, tree
):
617 """ x.symmetric_difference(t1) -> Tree with keys in either T and t1 but
620 thiskeys
= frozenset(self
.keys())
621 rkeys
= thiskeys
.symmetric_difference(frozenset(tree
.keys()))
622 return self
.__class
__( ((key
, self
.get(key
)) for key
in rkeys
) )
624 def issubset(self
, tree
):
625 """ x.issubset(tree) -> True if every element in x is in tree """
626 thiskeys
= frozenset(self
.keys())
627 return thiskeys
.issubset(frozenset(tree
.keys()))
629 def issuperset(self
, tree
):
630 """ x.issubset(tree) -> True if every element in tree is in x """
631 thiskeys
= frozenset(self
.keys())
632 return thiskeys
.issuperset(frozenset(tree
.keys()))
634 def isdisjoint(self
, tree
):
635 """ x.isdisjoint(S) -> True if x has a null intersection with tree """
636 thiskeys
= frozenset(self
.keys())
637 return thiskeys
.isdisjoint(frozenset(tree
.keys()))
640 def _build_sets(trees
):
641 return [ frozenset(tree
.keys()) for tree
in trees
]