import logging
import functools
import time
from binarytree import Node
logging.basicConfig(
level=logging.ERROR,
format='%(asctime)s-%(name)s-%(levelname)s-%(message)s')
logger = logging.getLogger(__name__)
def check_null(func):
@functools.wraps(func)
def wrapper(self, *args, **kw):
if self.__bool__():
return func(self, *args, **kw)
else:
if func.__name__ in ['_insert', '_insert2']:
self._root = Node(args[0])
else:
print('The tree is empty')
return wrapper
class BinarySearchTree():
"""如果非空,那么左子树的所有节点都小于根节点,右子树的所有节点都大于根节点,数为二叉搜索树。左右子树都为二叉搜索树。"""
def __init__(self):
self._root = None
def __str__(self):
tree2list = [x.data for x in self._generate_node()]
return 'the BinarySearchTree is%s' % tree2list
def __bool__(self):
if self._root is not None:
return True
else:
return False
@staticmethod
def _redirect(pre_node, is_left, target):
if is_left:
pre_node.left = target
else:
pre_node.right = target
def _generate_node(self):
queue = [self._root]
while queue:
node = queue.pop(0)
yield node
queue.extend([x for x in (node.left, node.right) if x != None])
@check_null
def _metal_find(self, value, node, alert=True):
# if you want the pre_node and is_left get the specific value, let the node=root
is_left, _pre_node = None, None
while node and value != node.data:
_pre_node = node
if value < node.data:
node = node.left
is_left = True
elif value > node.data:
node = node.right
is_left = False
if alert and node is None:
print('There is no node' % value)
return node, _pre_node, is_left
def find(self, value):
result, *_ = self._metal_find(value, self._root)
return result
@check_null
def _insert(self, value, node):
if node is None:
node = Node(value)
else:
if value < node.data:
node.left = self._insert(value, node.left)
elif value > node.data:
node.right = self._insert(value, node.right)
else:
print('have the same value')
return node
@check_null
def _insert2(self, value):
result, pre_node, is_left = self._metal_find(value, self._root, False)
if result is None:
self._redirect(pre_node, is_left, Node(value))
else:
print('already have the value')
# 默认走循环的实现, 递归的程序栈很容易爆掉,并且测试了下循环比递归快很多
def insert(self, value, isrecursion=False):
if isrecursion:
self._insert(value, self._root)
else:
self._insert2(value)
@check_null
def _find_extremum(self, node, by='max'):
if by=='max':
while node.right:
node = node.right
elif by=='min':
while node.left:
node = node.left
return node
def findmax(self):
return self._find_extremum(self._root)
def findmin(self):
return self._find_extremum(self._root, by='min')
@check_null
def _delete(self, value, node):
if not node:
print('can\'t find')
else:
if value < node.data:
node.left = self._delete(value, node.left)
elif value > node.data:
node.right = self._delete(value, node.right)
else:
# 有2个节点
if node.left and node.right:
tmp = self._find_extremum(node.left)
node.data = tmp.data
node.left = self._delete(tmp.data, node.left)
# 有1个或者没有
else:
if node.left is None:
node = node.right
else:
node = node.left
return node
@check_null
def _delete2(self, value, node):
result, pre_node, is_left = self._metal_find(value, node)
if result is None:
return
# 有2个节点的情况
if result.left and result.right:
tmp = self._find_extremum(result.left)
self._delete2(tmp.data, result)
result.data = tmp.data
# 有1个或者没有
else:
if result.left is None:
result = result.right
else:
result = result.left
self._redirect(pre_node, is_left, result)
def delete(self, value, isrecursion=False):
if isrecursion:
return self._delete(value, self._root)
else:
return self._delete2(value, self._root)
def test_insert(value):
def _test(value, control=False):
tree = BinarySearchTree()
start = time.time()
for i in range(value):
tree.insert(i, isrecursion=control)
end = time.time()
print('the isrecursion control=%s, the time is:%s' % (control, end-start))
_test(value)
_test(value, control=True)
def main():
# test_insert(100)
tree = BinarySearchTree()
nums = [7, 2, 9, 1, 4, 8, 10]
for i in nums:
tree.insert(i)
print(tree)
print(tree.find(4))
tree.insert(3)
print(tree)
tree.delete(2)
print(tree)
if __name__ == '__main__':
main()