文章目录
二叉树的 python 实现
class BinaryTree:
def __init__(self, data):
self._data = data # root node
self._left = None # left child
self._right = None
@property
def data(self):
return self._data
@data.setter
def data(self, data):
self._data = data
@property
def right(self):
return self._right
@right.setter
def right(self, right):
self._right = right
@property
def left(self):
return self._left
@left.setter
def left(self, left):
self._left = left
def insertLeft(self, newNode):
if self.left == None:
self.left = BinaryTree(newNode)
else:
temp = BinaryTree(newNode)
temp.left = self.left
self.left = temp
def insertRight(self, newNode):
if self.right == None:
self.right = BinaryTree(newNode)
else:
temp = BinaryTree(newNode)
temp.right = self.right
self.right = temp
二叉树的应用
- 编译器中的表达式树
- 霍夫曼编码树
- 二叉搜索树
- 优先队列
二叉树的常见问题
1. 树的遍历
1.1 先根遍历
def preorderRecursive(root, result):
if not root:
return
result.append(root.data)
preorderRecursive(root.left, result)
preorderRecursive(root.right, result)
def preorderIterative(root, result):
if not root:
return
stack = []
stack.append(root)
while stack:
node = stack.pop()
result.append(node.data)
if node.right:
stack.append(node.right)
if node.left:
stack.append(node.left)
1.2 中根遍历
def inorderRecursive(root, result):
if not root:
return
inorderRecursive(root.left, result)
result.append(root.data)
inorderRecursive(root.right, result)
def inorderIterative(root, result):
if not root:
return
stack = []
node = root
while stack or node:
if node:
stack.append(node)
node = node.left
else:
node = stack.pop()
result.append(node.data)
node = node.right
1.3 后根遍历
def postorderRecursive(root, result):
if not root:
return
postorderRecursive(root.left, result)
postorderRecursive(root.right, result)
result.append(root.data)
def postorderIterative(root, result):
if not root:
return
visited = set()
stack = []
node = root
while stack or node:
if node:
stack.append(node)
node = node.left
else:
node = stack.pop()
if node.right and not node.right in visited:
stack.append(node)
node = node.right
else:
visited.add(node)
result.append(node.data)
node = None
1.4 横向遍历
def levelOrder(root, result):
if root is None:
return
q = Queue()
q.enqueue(root)
while not q.isEmpty():
node = q.dequeue() # FIFO
result.append(node.data)
if node.left is not None:
q.enqueue(node.left)
if node.right is not None:
q.enqueue(node.right)
2. 找出树中的最大值
这类题目是醉翁之意不在酒,本质上是想考考你怎么遍历,在遍历的时候保留最大值即可。
def findMaxRecursive(root):
global maxData
if not root:
return
if root.data > maxData:
maxData = root.data
findMaxRecursive(root.left)
findMaxRecursive(root.right)
3. 插入节点
在横向遍历时插入节点
def insertInBinaryTreeUsingLevelOrder(root, data):
newNode = BinaryTree(data)
if root is None:
root = newNode
return root
q = Queue()
q.enQueue(root)
while not q.isEmpty():
node = q.deQueue()
if node.left is not None:
q.enQueue(node.left)
else:
node.left = newNode
return root
if node.right is not None:
q.enQueue(node.right)
else:
node.right = newNode
return root
4. 统计树的节点数
def findSizeRecursive(root):
if root is None:
return 0
return 1 + findSizeRecursive(root.left) + findSizeRecursive(root.right)
5. 统计树的深度
def maxDepth(root):
if root is None:
return 0
return 1 + maxDepth( maxDepth(root.left) , maxDepth(root.right) )
6. 找出最深的节点
横向搜索到的最后一个节点就是最深的
def deepestNode(root):
if root is None:
return None
q = Queue()
q.enQueue(root)
node = None
while not q.isEmpty():
node = q.deQueue()
if node.left is not None:
q.enQueue(node.left)
if node.right is not None:
q.enQueue(node.right)
return node
7. 删除节点
现将要删除的节点和最深的节点交换,然后删除最深的节点
8. 统计树的叶子数
横向搜索到最后一层,计数即可
def numberOfLeaves(root):
if root is None:
return 0
q = Queue()
q.enQueue(root)
count = 0
while not q.isEmpty():
node = q.deQueue()
if node.left is None and node.right is None:
count += 1
else:
if node.left is not None:
q.enQueue(node.left)
if node.right is not None:
q.enQueue(node.right)
return count
9. 最近公共祖先
Least Common Ancestors
def lca(root, alpha, beta):
if not root:
return None
if root.data == alpha or root.data == beta:
return root
left = lca(root.left, alpha, beta)
right = lca(root.right, alpha, beta)
if left and right: # alpha & beta are on both sides
return root
else:
return left if left else right
10. 利用 先根和中根序列 构造树
需要特别提醒,可以确定唯一树的情况有:
- 先序+中序
- 后序+中序
- 层序+中序
以下情况不能唯一确定:
- 先序+后序
- 先序+层序
- 后序+层序
def buildTree(preorder, inorder):
root = BinaryTree(preorder[0])
rootPos = inorder.index(preorder[0])
root.left = buildTree(preorder[1:1+rootPos], inorder[:rootPos])
root.right = buildTree(preorder[rootPos+1:], inorder[rootPos+1:])
return root
# 测试
root = buildTree('ABDECF','DBEAFC')
postOrder = []
postorderRecursive(root, postOrder)
assert(''.join(postOrder) == 'DEBFCA')
11. 判断两棵树是否同构
def isIsomorphic(root1, root2):
if(not root1 and not root2):
return True
if((not root1 and root2) or (root1 and not root2)):
return False
return (isIsomorphic(root1.left, root2.left) and isIsomorphic(root1.right, root2.right))
二叉搜索树
Binary Search Trees
基本操作:
- 插入
- 删除
- 查找
特点:
- BST 的 中根序列 是从小到大有序排列的
- BST 的查找效率取决于其深度,最好是 O(logn),最坏是 O(n)
平衡二叉搜索树
为了避免二叉搜索树的左右分支深度差异太大,在插入删除节点时,往往需要局部调整树的结构,保证树的深度始终是 O(logn)
常见的 平衡二叉搜索树 罗列如下:
- AVL 树
- 红黑树
- 伸展树(分裂树)Splay Tree
- B 树
- 替罪羊树 Scapegoat Trees
AVL树
Adelson-Velskii and Landis
- AVL 树是二叉搜索树
- AVL 树的左右子树的高度差至多为 1
- AVL 树的高度为 O(logn)
其它
一般树
- 一般树的子节点可以不止 2 个
- 一般树可以用二叉树来表示,此时二叉树的左右子节点分别存储一般树的 第一个孩子(firstChild) 和 下一个同辈(nextSibling)
线索二叉树
Threaded Binary Tree
充分利用冗余变量
表达式树
编译
异或(XOR)树
提升空间利用率