一、前言
树的术语是生物学、家谱学和几何学术语的一个特殊混合体。它很好的表示了层级结构,它的两个主要特征:
普通的树和二叉树的递归定义:
二、二叉搜索树(Binary Search Tree,BST)
在一个BST中,给定节点的左子树中的节点要小于它,其右子树中的节点要大于给定的节点。
2.1 二叉搜索树接口中的方法
BST方法 | 作用 |
tree.isEmpty() | 如果为空,返回True,否则返回False |
tree.__len__() | 返回树中元素的数目 |
tree.__iter__() | 对树进行一次前向遍历 |
tree.__str__() | 返回字符串,表示树的形状 |
tree.__contains__(item) | 如果item在树中,返回True,否则返回False |
tree.__add__(otherTree) | 返回一个新树,内容为tree和otherTree的内容 |
tree.__eq__(anyObject) | 若tree==otherTree,返回True,否则返回False |
tree.clear() | 让树变成空树 |
tree.add(item) | 将item添加到树中适当的位置 |
tree.remove(item) | 从树中删除item,先验条件:item在树中 |
tree.replace(item,newItem) | 使用newItem替代树中匹配的项,并返回匹配的项 |
tree.inorder() | 返回一个迭代器,对树执行中序遍历 |
tree.postorder() | 返回一个迭代器,对树执行后序遍历 |
tree.levelorder() | 返回一个迭代器,对树执行层序遍历 |
2.2代码实现
2.2.1 创建抽象集类,并保存为abstractcollection.py文件,具体代码见博客:https://blog.csdn.net/lzh_12345/article/details/79759960中的“二、利用链表实现栈”之2.1的代码。
2.2.2创建二叉搜索树节点类BSTNode,并保存为bstnode.py文件
class BSTNode(object):
"""Represents a node for a linked binary search tree."""
def __init__(self, data, left = None, right = None):
self.data = data
self.left = left
self.right = right
2.2.3创建LinkedStack和LinkedQueue类,并分别保存为linkedstack.py和linkedqueue.py文件。
LinkedStack类的具体代码:见博客:https://blog.csdn.net/lzh_12345/article/details/79759960中的“二、利用链表实现栈”。
LinkedQueue类的具体代码:见博客:https://blog.csdn.net/lzh_12345/article/details/79762861中的“二、队列的链表实现”。
2.2.4 链表实现BST
from abstractcollection import AbstractCollection
from bstnode import BSTNode
from linkedstack import LinkedStack
from linkedqueue import LinkedQueue
class LinkedBST(AbstractCollection):
"""An link-based binary search tree implementation."""
def __init__(self, sourceCollection = None):
"""Sets the initial state of self, which includes the
contents of sourceCollection, if it's present."""
self._root = None
AbstractCollection.__init__(self, sourceCollection)
# Accessor methods
def __str__(self):
"""Returns a string representation with the tree rotated
90 degrees counterclockwise."""
def recurse(node, level):
s = ""
if node != None:
s += recurse(node.right, level + 1)
s += "| " * level
s += str(node.data) + "\n"
s += recurse(node.left, level + 1)
return s
return recurse(self._root, 0)
def __iter__(self):
"""Supports a preorder traversal on a view of self."""
if not self.isEmpty():
stack = LinkedStack()
stack.push(self._root)
while not stack.isEmpty():
node = stack.pop()
yield node.data
if node.right != None:
stack.push(node.right)
if node.left != None:
stack.push(node.left)
def preorder(self):
"""Supports a preorder traversal on a view of self."""
return None
def inorder(self):
"""Supports an inorder traversal on a view of self."""
lyst = list()
def recurse(node):
if node != None:
recurse(node.left)
lyst.append(node.data)
recurse(node.right)
recurse(self._root)
return iter(lyst)
def postorder(self):
"""Supports a postorder traversal on a view of self."""
return None
def levelorder(self):
"""Supports a levelorder traversal on a view of self."""
return None
def __contains__(self, item):
"""Returns True if target is found or False otherwise."""
return self.find(item) != None
def find(self, item):
"""If item matches an item in self, returns the
matched item, or None otherwise."""
def recurse(node):
if node is None:
return None
elif item == node.data:
return node.data
elif item < node.data:
return recurse(node.left)
else:
return recurse(node.right)
return recurse(self._root)
# Mutator methods
def clear(self):
"""Makes self become empty."""
self._root = None
self._size = 0
def add(self, item):
"""Adds item to the tree."""
# Helper function to search for item's position
def recurse(node):
# New item is less, go left until spot is found
if item < node.data:
if node.left == None:
node.left = BSTNode(item)
else:
recurse(node.left)
# New item is greater or equal,
# go right until spot is found
elif node.right == None:
node.right = BSTNode(item)
else:
recurse(node.right)
# End of recurse
# Tree is empty, so new item goes at the root
if self.isEmpty():
self._root = BSTNode(item)
# Otherwise, search for the item's spot
else:
recurse(self._root)
self._size += 1
def remove(self, item):
"""Precondition: item is in self.
Raises: KeyError if item is not in self.
postcondition: item is removed from self."""
if not item in self:
raise KeyError("Item not in tree.""")
# Helper function to adjust placement of an item
def liftMaxInLeftSubtreeToTop(top):
# Replace top's datum with the maximum datum in the left subtree
# Pre: top has a left child
# Post: the maximum node in top's left subtree
# has been removed
# Post: top.data = maximum value in top's left subtree
parent = top
currentNode = top.left
while not currentNode.right == None:
parent = currentNode
currentNode = currentNode.right
top.data = currentNode.data
if parent == top:
top.left = currentNode.left
else:
parent.right = currentNode.left
# Begin main part of the method
if self.isEmpty(): return None
# Attempt to locate the node containing the item
itemRemoved = None
preRoot = BSTNode(None)
preRoot.left = self._root
parent = preRoot
direction = 'L'
currentNode = self._root
while not currentNode == None:
if currentNode.data == item:
itemRemoved = currentNode.data
break
parent = currentNode
if currentNode.data > item:
direction = 'L'
currentNode = currentNode.left
else:
direction = 'R'
currentNode = currentNode.right
# Return None if the item is absent
if itemRemoved == None: return None
# The item is present, so remove its node
# Case 1: The node has a left and a right child
# Replace the node's value with the maximum value in the
# left subtree
# Delete the maximium node in the left subtree
if not currentNode.left == None \
and not currentNode.right == None:
liftMaxInLeftSubtreeToTop(currentNode)
else:
# Case 2: The node has no left child
if currentNode.left == None:
newChild = currentNode.right
# Case 3: The node has no right child
else:
newChild = currentNode.left
# Case 2 & 3: Tie the parent to the new child
if direction == 'L':
parent.left = newChild
else:
parent.right = newChild
# All cases: Reset the root (if it hasn't changed no harm done)
# Decrement the collection's size counter
# Return the item
self._size -= 1
if self.isEmpty():
self._root = None
else:
self._root = preRoot.left
return itemRemoved
def replace(self, item, newItem):
"""
If item is in self, replaces it with newItem and
returns the old item, or returns None otherwise."""
probe = self._root
while probe != None:
if probe.data == item:
oldData = probe.data
probe.data = newItem
return oldData
elif probe.data > item:
probe = probe.left
else:
probe = probe.right
return None
2.2.5 测试文件
from linkedbst import LinkedBST
def main():
tree = LinkedBST()
print("Adding D B A C F E G")
tree.add("D")
tree.add("B")
tree.add("A")
tree.add("C")
tree.add("F")
tree.add("E")
tree.add("G")
print("\nExpect True for A in tree: ", "A" in tree)
print("\nString:\n" + str(tree))
clone = LinkedBST(tree)
print("\nClone:\n" + str(clone))
print("Expect True for tree == clone: ", tree == clone)
print("\nFor loop: ", end="")
for item in tree:
print(item, end=" ")
print("\n\ninorder traversal: ", end="")
for item in tree.inorder(): print(item, end = " ")
print("\n\npreorder traversal: ", end="")
for item in tree.preorder(): print(item, end = " ")
print("\n\npostorder traversal: ", end="")
for item in tree.postorder(): print(item, end = " ")
print("\n\nlevelorder traversal: ", end="")
for item in tree.levelorder(): print(item, end = " ")
print("\n\nRemoving all items:", end = " ")
for item in "ABCDEFG":
print(tree.remove(item), end=" ")
print("\n\nExpect 0: ", len(tree))
tree = LinkedBST(range(1, 16))
print("\nAdded 1..15:\n" + str(tree))
lyst = list(range(1, 16))
import random
random.shuffle(lyst)
tree = LinkedBST(lyst)
print("\nAdded ", lyst, "\n" + str(tree))
if __name__ == "__main__":
main()