前面一篇我們介紹了二叉樹的廣度優先添加和遍歷元素,在二叉樹的遍歷技術中,除了廣度優先遍歷,還有一種叫深度優先遍歷。本篇就來討論深度遍歷的三種重要的方法,它們分別是先序遍歷和中序遍歷和後序遍歷。
1.三種深度遍歷的概念
深度遍歷有重要的三種方法,這三種方式常被用於訪問樹的節點。它們之間不同在於訪問每個節點的次序不同。這三種遍歷分別叫做先序遍歷(preorder),中序遍歷(inorder)和後序遍歷(postorder).
先序遍歷
在先序遍歷中,我們先訪問根節點,然後遞歸使用先序遍歷訪問左子樹,再遞歸使用先序遍歷訪問右子樹。
根節點->左子樹->右子樹
中序遍歷
遞歸使用中序遍歷先訪問左子樹,然後訪問根節點,最壞遞歸使用中序訪問右子樹。
左子樹->根節點->右子樹
後序遍歷
遞歸使用後序遍歷先訪問左子樹,然後遞歸使用後序遍歷訪問右子樹,最後訪問根節點。
左子樹->右子樹->根節點
2.具體一顆二叉樹的三種深度遍歷分析
下面給出一個具體二叉樹,然後我們利用上面的概念,來寫出遍歷輸出元素的順序。
這個按照前面的廣度優先遍歷輸出元素的順序是:0 1 2 3 4 5 6 7 8 9
先序遍歷
先序遍歷順序是先根節點,然後左子樹,然後右子樹。我們這裏拿先序遍歷重點介紹這個思路分析過程。
第一步,遍歷根節點,輸出 0
第二步,發現左節點1下形成一個左子樹,右邊節點2也是一顆樹。左子樹優先右子樹遍歷,所以第二個輸出 1
第三步,遍歷發現3 4節點,左子樹優先元素,輸出 3
第四步,遍歷7 8 節點,輸出7
第五步,在 378這個子樹,剩下8這個右節點,所以輸出 8
第六步,因爲3節點已經遍歷過,這裏遍歷輸出 4
第七步,4節點的只有9這個節點,輸出 9
第八步,到這裏 1節點下左子樹全部遍歷完成,這裏開始遍歷2子樹,這裏輸出 2
第九步,5 6節點,左邊優先,輸出 5
第十步,輸出 6
所以先序遍歷輸出元素順序爲:0 1 3 7 8 4 9 2 5 6
中序遍歷
根據遇到一棵樹,先左子樹->根節點-右子樹規則
遍歷元素順序爲:7 3 8 1 9 4 0 5 2 6
後序遍歷
根據遇到一棵樹,先左子樹->右子樹->根節點 規則
遍歷元素順序爲:7 8 3 9 4 1 5 6 2 0
3.代碼實現三種深度遍歷
下面接着上一篇python代碼,來寫先序 中序 後序三種遍歷的代碼。
先序遍歷實現
# coding:utf-8
class Node(object):
"""節點"""
def __init__(self, itme):
self.ele = itme
self.lchild = None
self.rchild = None
class BinaryTree(object):
"""二叉樹"""
def __init__(self):
self.root = None
def add(self, item):
node = Node(item)
if self.root is None:
self.root = node
return
# 一個隊列,添加根元素
queue = [self.root]
while queue:
cur_node = queue.pop(0)
if cur_node.lchild is None:
cur_node.lchild = node
return
else:
queue.append(cur_node.lchild)
if cur_node.rchild is None:
cur_node.rchild = node
return
else:
queue.append(cur_node.rchild)
def breadth_travle(self):
"""廣度遍歷"""
if self.root is None:
return
queue = [self.root]
while queue:
cur_node = queue.pop(0)
print(cur_node.ele, end=" ")
if cur_node.lchild is not None:
queue.append(cur_node.lchild)
if cur_node.rchild is not None:
queue.append(cur_node.rchild)
def preorder(self, node):
"""先序遍歷,node 是根節點"""
if node is None:
return
print(node.ele, end=" ")
self.preorder(node.lchild)
self.preorder(node.rchild)
if __name__ == "__main__":
tree = BinaryTree()
tree.add(0)
tree.add(1)
tree.add(2)
tree.add(3)
tree.add(4)
tree.add(5)
tree.add(6)
tree.add(7)
tree.add(8)
tree.add(9)
tree.breadth_travle()
print(" ")
tree.preorder(tree.root)
運行結果
0 1 2 3 4 5 6 7 8 9
0 1 3 7 8 4 9 2 5 6
第一個是廣度遍歷順序,第二行是先序遍歷結果。
中序遍歷代碼
上面知道了先序遍歷,那麼中序遍歷就簡單了,調整以下這行打印順序就行。
# coding:utf-8
class Node(object):
"""節點"""
def __init__(self, itme):
self.ele = itme
self.lchild = None
self.rchild = None
class BinaryTree(object):
"""二叉樹"""
def __init__(self):
self.root = None
def add(self, item):
node = Node(item)
if self.root is None:
self.root = node
return
# 一個隊列,添加根元素
queue = [self.root]
while queue:
cur_node = queue.pop(0)
if cur_node.lchild is None:
cur_node.lchild = node
return
else:
queue.append(cur_node.lchild)
if cur_node.rchild is None:
cur_node.rchild = node
return
else:
queue.append(cur_node.rchild)
def breadth_travle(self):
"""廣度遍歷"""
if self.root is None:
return
queue = [self.root]
while queue:
cur_node = queue.pop(0)
print(cur_node.ele, end=" ")
if cur_node.lchild is not None:
queue.append(cur_node.lchild)
if cur_node.rchild is not None:
queue.append(cur_node.rchild)
def preorder(self, node):
"""先序遍歷,node 是根節點"""
if node is None:
return
print(node.ele, end=" ")
self.preorder(node.lchild)
self.preorder(node.rchild)
def inorder(self, node):
"""中序遍歷"""
if node is None:
return
self.inorder(node.lchild)
print(node.ele, end=" ")
self.inorder(node.rchild)
if __name__ == "__main__":
tree = BinaryTree()
tree.add(0)
tree.add(1)
tree.add(2)
tree.add(3)
tree.add(4)
tree.add(5)
tree.add(6)
tree.add(7)
tree.add(8)
tree.add(9)
tree.breadth_travle()
print(" ")
tree.preorder(tree.root)
print(" ")
tree.inorder(tree.root)
運行結果
0 1 2 3 4 5 6 7 8 9
0 1 3 7 8 4 9 2 5 6
7 3 8 1 9 4 0 5 2 6
第三行是中序結果,下面直接貼出後續代碼。
# coding:utf-8
class Node(object):
"""節點"""
def __init__(self, itme):
self.ele = itme
self.lchild = None
self.rchild = None
class BinaryTree(object):
"""二叉樹"""
def __init__(self):
self.root = None
def add(self, item):
node = Node(item)
if self.root is None:
self.root = node
return
# 一個隊列,添加根元素
queue = [self.root]
while queue:
cur_node = queue.pop(0)
if cur_node.lchild is None:
cur_node.lchild = node
return
else:
queue.append(cur_node.lchild)
if cur_node.rchild is None:
cur_node.rchild = node
return
else:
queue.append(cur_node.rchild)
def breadth_travle(self):
"""廣度遍歷"""
if self.root is None:
return
queue = [self.root]
while queue:
cur_node = queue.pop(0)
print(cur_node.ele, end=" ")
if cur_node.lchild is not None:
queue.append(cur_node.lchild)
if cur_node.rchild is not None:
queue.append(cur_node.rchild)
def preorder(self, node):
"""先序遍歷,node 是根節點"""
if node is None:
return
print(node.ele, end=" ")
self.preorder(node.lchild)
self.preorder(node.rchild)
def inorder(self, node):
"""中序遍歷"""
if node is None:
return
self.inorder(node.lchild)
print(node.ele, end=" ")
self.inorder(node.rchild)
def postorder(self, node):
"""中序遍歷"""
if node is None:
return
self.postorder(node.lchild)
self.postorder(node.rchild)
print(node.ele, end=" ")
if __name__ == "__main__":
tree = BinaryTree()
tree.add(0)
tree.add(1)
tree.add(2)
tree.add(3)
tree.add(4)
tree.add(5)
tree.add(6)
tree.add(7)
tree.add(8)
tree.add(9)
tree.breadth_travle()
print(" ")
tree.preorder(tree.root)
print(" ")
tree.inorder(tree.root)
print(" ")
tree.postorder(tree.root)
運行結果
0 1 2 3 4 5 6 7 8 9
0 1 3 7 8 4 9 2 5 6
7 3 8 1 9 4 0 5 2 6
7 8 3 9 4 1 5 6 2 0