blob: 866dc89d20832d30234423d803db58f6806cd2c6 [file] [log] [blame]
#!/usr/bin/env python
#coding:utf-8
# Author: mozman
# Purpose: binary tree module
# Created: 28.04.2010
# Copyright (c) 2010-2013 by Manfred Moitzi
# License: MIT License
from __future__ import absolute_import
from .treemixin import TreeMixin
__all__ = ['BinaryTree']
class Node(object):
""" Internal object, represents a treenode """
__slots__ = ['key', 'value', 'left', 'right']
def __init__(self, key, value):
self.key = key
self.value = value
self.left = None
self.right = None
def __getitem__(self, key):
""" x.__getitem__(key) <==> x[key], where key is 0 (left) or 1 (right) """
return self.left if key == 0 else self.right
def __setitem__(self, key, value):
""" x.__setitem__(key, value) <==> x[key]=value, where key is 0 (left) or 1 (right) """
if key == 0:
self.left = value
else:
self.right = value
def free(self):
""" Set references to None """
self.left = None
self.right = None
self.value = None
self.key = None
class BinaryTree(TreeMixin):
"""
BinaryTree implements an unbalanced binary tree with a dict-like interface.
see: http://en.wikipedia.org/wiki/Binary_tree
A binary tree is a tree data structure in which each node has at most two
children.
BinaryTree() -> new empty tree.
BinaryTree(mapping,) -> new tree initialized from a mapping
BinaryTree(seq) -> new tree initialized from seq [(k1, v1), (k2, v2), ... (kn, vn)]
see also TreeMixin() class.
"""
def __init__(self, items=None):
""" x.__init__(...) initializes x; see x.__class__.__doc__ for signature """
self._root = None
self._count = 0
if items is not None:
self.update(items)
def clear(self):
""" T.clear() -> None. Remove all items from T. """
def _clear(node):
if node is not None:
_clear(node.left)
_clear(node.right)
node.free()
_clear(self._root)
self._count = 0
self._root = None
@property
def root(self):
""" root node of T """
return self._root
@property
def count(self):
""" count of items """
return self._count
def _new_node(self, key, value):
""" Create a new tree node. """
self._count += 1
return Node(key, value)
def insert(self, key, value):
""" T.insert(key, value) <==> T[key] = value, insert key, value into Tree """
if self._root is None:
self._root = self._new_node(key, value)
else:
parent = None
direction = 0
node = self._root
while True:
if node is None:
parent[direction] = self._new_node(key, value)
break
if key == node.key:
node.value = value # replace value
break
else:
parent = node
direction = 0 if key <= node.key else 1
node = node[direction]
def remove(self, key):
""" T.remove(key) <==> del T[key], remove item <key> from tree """
node = self._root
if node is None:
raise KeyError(str(key))
else:
parent = None
direction = 0
while True:
if key == node.key:
# remove node
if (node.left is not None) and (node.right is not None):
# find replacment node: smallest key in right-subtree
parent = node
direction = 1
replacement = node.right
while replacement.left is not None:
parent = replacement
direction = 0
replacement = replacement.left
parent[direction] = replacement.right
#swap places
node.key = replacement.key
node.value = replacement.value
node = replacement # delete replacement!
else:
down_dir = 1 if node.left is None else 0
if parent is None: # root
self._root = node[down_dir]
else:
parent[direction] = node[down_dir]
node.free()
self._count -= 1
break
else:
direction = 0 if key < node.key else 1
parent = node
node = node[direction]
if node is None:
raise KeyError(str(key))