刷題筆記:樹的前序、中序、後序遍歷
在此之前,我們定義二叉樹的資料結構如下:
class TreeNode//節點結構
{
int value;
List<TreeNode> children=new ArrayList<>();
TreeNode left;
TreeNode right;
TreeNode(int value)
{
this.value = value;
}
}
//主函式
public class main {
public static List<Integer> res=new ArrayList<>();
public static void main(String[] args) {
//以下為前序後續遍歷N叉樹建樹的過程
TreeNode[] node = new TreeNode[10];//以陣列形式生成一棵完全二叉樹
for(int i = 0; i < 10; i++)
{
node[i] = new TreeNode(i);
}
//建樹
for(int i = 0; i < 10; i++)
{
if(i*2+1 < 10)
node[i].children.add(node[i*2+1]);
if(i*2+2 < 10)
node[i].children.add(node[i*2+2]);
}
// 註釋部分適用於中序遍歷二叉樹建立樹結構
// TreeNode[] node = new TreeNode[10];
// for(int i = 0; i < 10; i++)
// {
// node[i] = new TreeNode(i);
// }
// for(int i = 0; i < 10; i++)
// {
// if(i*2+1 < 10)
// node[i].left = node[i*2+1];
// if(i*2+2 < 10)
// node[i].right = node[i*2+2];
// }
// System.out.println("前序遞迴");
// PreOrder.preOrderRecursion(node[0],res);
// System.out.println(res.toString());
//
// System.out.println("前序非遞迴");
// List<Integer> resultPre=PreOrder.preOrder(node[0]);
// System.out.println(resultPre.toString());
// System.out.println("中序遞迴");
// MidOrder.midOrderRecursion(node[0],res);
// System.out.println(res.toString());
//
// System.out.println("中序非遞迴");
// List<Integer> resultMid=MidOrder.midOrder(node[0]);
// System.out.println(resultMid.toString());
System.out.println("後序遞迴");
LateOrder.postOrderRe(node[0],res);
System.out.println(res.toString());
System.out.println("後序非遞迴");
List<Integer> resultMid=LateOrder.postOrder(node[0]);
System.out.println(resultMid.toString());
}
}
前序遍歷
前序遍歷又稱先根遍歷,遍歷順序是根->左->右。遍歷步驟是:
若 二叉樹為空則結束返回,否則:
(1)訪問根結點。
(2)前序遍歷左子樹 。
(3)前序遍歷右子樹 。
上圖的前序遍歷為:ABDECF.
注意:已知後序遍歷和中序遍歷,就能確定前序遍歷。
遞迴
public static void preOrderRecursion(TreeNode treeNode,List<Integer> res){
List<TreeNode> children=treeNode.children;
res.add(treeNode.value);
for(TreeNode node:children){
if(node!=null){
preOrderRecursion(node,res);
}
}
}
非遞迴
//非遞迴,需要依靠棧實現
public static List<Integer> preOrder(TreeNode treeNode){
Stack<TreeNode> stack=new Stack<>();
List<Integer> res=new ArrayList<>();
stack.add(treeNode);
while (!stack.isEmpty()){
TreeNode root=stack.pop();
res.add(root.value);
Collections.reverse(root.children);
for(TreeNode child:root.children){
stack.add(child);
}
}
return res;
}
中序遍歷
中序遍歷又稱中根遍歷,遍歷順序是左->根->右。
若二叉樹為空則結束返回,
否則:
(1)中序遍歷左子樹
(2)訪問根結點
(3)中序遍歷右子樹
上圖的中序遍歷結果為:DBEAFC
遞迴
public static void midOrderRecursion(TreeNode treeNode, List<Integer> res){
if (treeNode==null)
return;
else{
midOrderRecursion(treeNode.left, res);
res.add(treeNode.value);
midOrderRecursion(treeNode.right, res);
}
}
非遞迴
//非遞迴,需要依靠棧實現
public static List<Integer> midOrder(TreeNode treeNode){
Stack<TreeNode> stack=new Stack<>();
List<Integer> res=new ArrayList<>();
while(treeNode != null || !stack.isEmpty()){
while (treeNode!=null){
stack.push(treeNode);
treeNode = treeNode.left;
}
if(!stack.isEmpty()){
treeNode=stack.pop();
res.add(treeNode.value);
treeNode = treeNode.right;
}
}
return res;
}
後續遍歷
後續遍歷,又稱後根遍歷。即先輸出孩子節點,後輸出跟節點,遍歷順序左->右->根。
若二叉樹為空則結束返回,
否則:
(1)後序遍歷左子樹
(2)後序遍歷右子樹
(3)訪問根結點
遞迴
public static void postOrderRe(TreeNode treeNode, List<Integer> res)
{//後序遍歷遞迴實現
if(treeNode == null)
return;
else
{
List<TreeNode> children=treeNode.children;
for(TreeNode node:children){
if(node!=null){
postOrderRe(node,res);
}
}
res.add(treeNode.value);
}
}
非遞迴
後續遍歷的非遞迴演算法與前序遍歷的非遞迴演算法很像。我們舉個例子:
在後序遍歷中,我們會先遍歷一個節點的所有子節點,再遍歷這個節點本身。例如當前的節點為 u,它的子節點為 v1, v2, v3
時,那麼後序遍歷的結果為 [children of v1], v1, [children of v2], v2, [children of v3], v3, u
,其中 [children of vk]
表示以 vk
為根節點的子樹的後序遍歷結果(不包括 vk 本身)。我們將這個結果反轉,可以得到 u, v3, [children of v3]', v2, [children of v2]', v1, [children of v1]'
,其中 [a]’ 表示 [a] 的反轉。此時我們發現,結果和前序遍歷非常類似,只不過前序遍歷中對子節點的遍歷順序是 v1, v2, v3
,而這裡是 v3, v2, v1
。
因此我們可以使用和 N叉樹的前序遍歷
相同的方法,使用一個棧來得到後序遍歷。我們首先把根節點入棧。當每次我們從棧頂取出一個節點 u
時,就把 u
的所有子節點順序推入棧中。例如 u
的子節點從左到右為 v1, v2, v3
,那麼推入棧的順序應當為 v1, v2, v3
,這樣就保證了下一個遍歷到的節點(即 u
的第一個子節點 v3
)出現在棧頂的位置。在遍歷結束之後,我們把遍歷結果反轉,就可以得到後序遍歷。(以上參考Leetcode題解)
public static List<Integer> postOrder(TreeNode treeNode)
{
Stack<TreeNode> stack = new Stack<>();
List<Integer> output = new ArrayList<>();
if (treeNode == null) {
return output;
}
stack.add(treeNode);
while (!stack.isEmpty()) {
TreeNode node = stack.pop();
output.add(node.value);
for (TreeNode item : node.children) {
if (item != null) {
stack.push(item);
}
}
}
Collections.reverse(output);
return output;
}
相關文章
- 二叉樹的建立、前序遍歷、中序遍歷、後序遍歷二叉樹
- 二叉樹建立,前序遍歷,中序遍歷,後序遍歷 思路二叉樹
- 二叉樹的前序、中序、後序三種遍歷二叉樹
- 二叉樹的前序,中序,後序遍歷方法總結二叉樹
- 資料結構與演算法——二叉樹的前序遍歷,中序遍歷,後序遍歷資料結構演算法二叉樹
- 【樹01】對二叉樹前序/中序/後序遍歷演算法的一些思考二叉樹演算法
- 144.二叉樹的前序遍歷145.二叉樹的後序遍歷 94.二叉樹的中序遍歷二叉樹
- 二叉樹迭代器(中序遞迴、前序和後序遍歷)演算法二叉樹遞迴演算法
- 根據前序遍歷序列、中序遍歷序列,重建二叉樹二叉樹
- LintCode 前序遍歷和中序遍歷樹構造二叉樹二叉樹
- 二叉樹 前序、中序、後序二叉樹
- 刷題系列 - 給出前序和後序遍歷佇列,構造對應二叉樹佇列二叉樹
- 刷題系列 - 中序和後序遍歷佇列,構造對應二叉樹;佇列二叉樹
- 【資料結構與演算法】二叉樹的 Morris 遍歷(前序、中序、後序)資料結構演算法二叉樹
- 二叉樹前序、中序、後序遍歷相互求法(code留著看,概念先看了)二叉樹
- 【二叉樹】前中序求後序,中後序求前序二叉樹
- 根據二叉樹的前序遍歷和中序遍歷輸出二叉樹;二叉樹
- 關於二叉樹的前序遍歷、中序遍歷、刪除元素、插入元素二叉樹
- 二叉樹的四種遍歷方法:先序,中序,後序,層序二叉樹
- 二叉樹中序和後序遍歷表示式二叉樹
- 二叉樹的先,中,後序遍歷二叉樹
- 二叉樹的先中後序遍歷二叉樹
- 二叉樹的前中後序遍歷二叉樹
- 二叉樹--後序遍歷二叉樹
- 889. 根據前序和後序遍歷構造二叉樹二叉樹
- 從中序與後序遍歷序列構造二叉樹二叉樹
- 演算法 -- 實現二叉樹先序,中序和後序遍歷演算法二叉樹
- 力扣#94 樹的中序遍歷力扣
- 二叉樹 ---- 前序 中序 後序 知二求一二叉樹
- 後序+中序(前序+中序)重構樹,嚴格O(N)演算法演算法
- 非遞迴遍歷二叉樹的四種策略-先序、中序、後序和層序遞迴二叉樹
- 力扣工作周刷題 - 94. 二叉樹的中序遍歷力扣二叉樹
- Construct Binary Tree from Preorder and Inorder Traversal(前序遍歷和中序遍歷樹構造二叉樹)...Struct二叉樹
- 遞迴和迭代實現二叉樹先序、中序、後序和層序遍歷遞迴二叉樹
- ast 後序遍歷AST
- 二叉樹:構造二叉樹(通過前序和中序遍歷)、映象翻轉、層次遍歷二叉樹
- 【模板題】- 94. 二叉樹的中序遍歷二叉樹
- PAT 1043 Is It a Binary Search Tree (25分) 由前序遍歷得到二叉搜尋樹的後序遍歷