12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#!/usr/bin/env python
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#coding:utf-8
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# Author:  mozman
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# Purpose: binary tree module
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# Created: 28.04.2010
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# Copyright (c) 2010-2013 by Manfred Moitzi
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# License: MIT License
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)from __future__ import absolute_import
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)from .treemixin import TreeMixin
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)__all__ = ['BinaryTree']
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class Node(object):
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """ Internal object, represents a treenode """
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    __slots__ = ['key', 'value', 'left', 'right']
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    def __init__(self, key, value):
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        self.key = key
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        self.value = value
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        self.left = None
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        self.right = None
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    def __getitem__(self, key):
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        """ x.__getitem__(key) <==> x[key], where key is 0 (left) or 1 (right) """
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return self.left if key == 0 else self.right
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    def __setitem__(self, key, value):
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        """ x.__setitem__(key, value) <==> x[key]=value, where key is 0 (left) or 1 (right) """
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if key == 0:
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            self.left = value
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        else:
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            self.right = value
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    def free(self):
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        """ Set references to None """
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        self.left = None
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        self.right = None
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        self.value = None
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        self.key = None
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class BinaryTree(TreeMixin):
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    BinaryTree implements an unbalanced binary tree with a dict-like interface.
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    see: http://en.wikipedia.org/wiki/Binary_tree
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    A binary tree is a tree data structure in which each node has at most two
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    children.
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    BinaryTree() -> new empty tree.
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    BinaryTree(mapping,) -> new tree initialized from a mapping
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    BinaryTree(seq) -> new tree initialized from seq [(k1, v1), (k2, v2), ... (kn, vn)]
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    see also TreeMixin() class.
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    def __init__(self, items=None):
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        """ x.__init__(...) initializes x; see x.__class__.__doc__ for signature """
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        self._root = None
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        self._count = 0
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if items is not None:
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            self.update(items)
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    def clear(self):
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        """ T.clear() -> None.  Remove all items from T. """
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        def _clear(node):
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            if node is not None:
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                _clear(node.left)
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                _clear(node.right)
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                node.free()
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        _clear(self._root)
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        self._count = 0
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        self._root = None
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    @property
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    def root(self):
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        """ root node of T """
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return self._root
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    @property
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    def count(self):
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        """ count of items """
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return self._count
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    def _new_node(self, key, value):
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        """ Create a new tree node. """
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        self._count += 1
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return Node(key, value)
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    def insert(self, key, value):
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        """ T.insert(key, value) <==> T[key] = value, insert key, value into Tree """
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if self._root is None:
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            self._root = self._new_node(key, value)
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        else:
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            parent = None
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            direction = 0
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            node = self._root
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            while True:
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                if node is None:
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    parent[direction] = self._new_node(key, value)
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    break
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                if key == node.key:
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    node.value = value  # replace value
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    break
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                else:
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    parent = node
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    direction = 0 if key <= node.key else 1
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    node = node[direction]
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    def remove(self, key):
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        """ T.remove(key) <==> del T[key], remove item <key> from tree """
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        node = self._root
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if node is None:
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            raise KeyError(str(key))
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        else:
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            parent = None
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            direction = 0
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            while True:
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                if key == node.key:
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    # remove node
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    if (node.left is not None) and (node.right is not None):
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        # find replacment node: smallest key in right-subtree
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        parent = node
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        direction = 1
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        replacement = node.right
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        while replacement.left is not None:
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            parent = replacement
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            direction = 0
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            replacement = replacement.left
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        parent[direction] = replacement.right
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        #swap places
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        node.key = replacement.key
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        node.value = replacement.value
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        node = replacement  # delete replacement!
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    else:
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        down_dir = 1 if node.left is None else 0
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        if parent is None:  # root
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            self._root = node[down_dir]
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        else:
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            parent[direction] = node[down_dir]
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    node.free()
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    self._count -= 1
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    break
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                else:
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    direction = 0 if key < node.key else 1
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    parent = node
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    node = node[direction]
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    if node is None:
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        raise KeyError(str(key))
154