生活随笔
收集整理的這篇文章主要介紹了
二叉树的前序遍历、中序遍历、后序遍历
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
提示:文章寫完后,目錄可以自動生成,如何生成可參考右邊的幫助文檔
文章目錄
- 為什么需要樹這種數據結構
- 樹的常用術語
- 二叉樹的概念
- 二叉樹遍歷的說明
- 實現二叉樹
- 實現二叉樹的遍歷
- 二叉樹查找結點
- 二叉樹-刪除節點
為什么需要樹這種數據結構
1、數組存儲方式的分析
優點:通過下標方式訪問元素,速度快。對于有序數組,還可使用二分查找提高檢索速度。
缺點:如果要檢索具體某個值,或者插入值(按一定順序)會整體移動,效率較低
2、鏈式存儲方式的分析
優點:在一定程度上對數組存儲方式有優化(比如:插入一個數值節點,只需要將插入節點,鏈接到鏈表中即可, 刪除效率也很好)。
缺點:在進行檢索時,效率仍然較低,比如(檢索某個值,需要從頭節點開始遍歷)
3、樹存儲方式的分析
能提高數據存儲,讀取的效率, 比如利用 二叉排序樹(Binary Sort Tree),既可以保證數據的檢索速度,同時也可以保證數據的插入,刪除,修改的速度。案例: [7, 3, 10, 1, 5, 9, 12]
樹的常用術語
- 節點
- 根節點
- 父節點
- 子節點
- 葉子節點 (沒有子節點的節點)
- 節點的權(節點值)
- 路徑(從root節點找到該節點的路線)
- 層
- 子樹
- 樹的高度(最大層數)
- 森林 :多顆子樹構成森林
二叉樹的概念
- 樹有很多種,每個節點最多只能有兩個子節點的一種形式稱為二叉樹。
- 二叉樹的子節點分為左節點和右節點。
- 如果該二叉樹的所有葉子節點都在最后一層,并且結點總數= 2^n -1 , n 為層數,則我們稱為滿二叉樹。
- 如果該二叉樹的所有葉子節點都在最后一層或者倒數第二層,而且最后一層的葉子節點在左邊連續,倒數第二層的葉子節點在右邊連續,我們稱為完全二叉樹。
二叉樹遍歷的說明
以下三種遍歷都是從root結點開始,遍歷的過程使用了迭代的思想
- 前序遍歷
先輸出當前結點,再遍歷左子樹和右子樹 - 中序遍歷
先遍歷左子樹,再輸出當前節點,再遍歷右子樹 - 后序遍歷
先遍歷左子樹,再遍歷右子樹,最后輸出當前節點
小結: 看輸出父節點的順序,就確定是前序,中序還是后序
實現二叉樹
以下面這個圖為例子,我們實現一個二叉樹
- 首先定義樹的結點Node,我們給樹的結點中定義幾個必不可少的信息,一個是權重no,一個是值name(我們用name表示角色名稱),zhe每個結點都存在一個指向左子樹的指針和一個指向右子樹的指針,這里我們結點的屬性中用left和right表示,都是結點類型
class HeroNode {private int no
;private String name
;private HeroNode left
; private HeroNode right
; public HeroNode(int no
, String name
) {this.no
= no
;this.name
= name
;}public int getNo() {return no
;}public void setNo(int no
) {this.no
= no
;}public String getName() {return name
;}public void setName(String name
) {this.name
= name
;}public HeroNode getLeft() {return left
;}public void setLeft(HeroNode left
) {this.left
= left
;}public HeroNode getRight() {return right
;}public void setRight(HeroNode right
) {this.right
= right
;}@Overridepublic String toString() {return "HeroNode [no=" + no
+ ", name=" + name
+ "]";}
}
- 結點創建好后,我們定義樹類,因為每個二叉樹都有一個根結點,所以我們再樹類中需要定義一個根節點屬性,提供給用戶在創建二叉樹的時候,指定根節點
class BinaryTree {private HeroNode root
;public void setRoot(HeroNode root
) {this.root
= root
;}
}
- 用戶根據上述HeroNode 和BinaryTree實現上圖中的二叉樹
public static void main(String[] args
) {BinaryTree binaryTree
= new BinaryTree();HeroNode root
= new HeroNode(1, "宋江");HeroNode node2
= new HeroNode(2, "吳用");HeroNode node3
= new HeroNode(3, "盧俊義");HeroNode node4
= new HeroNode(4, "林沖");root
.setLeft(node2
);root
.setRight(node3
);node3
.setRight(node4
);binaryTree
.setRoot(root
); }
實現二叉樹的遍歷
二叉樹的實現還是比較簡單的,我們在上面二叉樹的基礎之上,新添加一個結點,如圖
并實現二叉樹的三種遍歷方式,我們再回顧下三種遍歷方式,同時我會指出上圖,在各種遍歷方式下的結果,方便我們用代碼實現時進行比對
- 前序遍歷:從root結點開始,先輸出當前結點,再遍歷左子樹和右子樹(跌代)
1 2 3 5 4
- 中序遍歷:從root結點開始,先遍歷左子樹,再輸出當前結點,再遍歷右子樹
2 1 5 3 4
- 后序遍歷:從root結點開始,先遍歷左子樹,再遍歷右子樹,最后輸出當前結點
2 5 4 3 1
下面開始代碼實現:
class HeroNode {private int no
;private String name
;private HeroNode left
; private HeroNode right
; public HeroNode(int no
, String name
) {this.no
= no
;this.name
= name
;}public int getNo() {return no
;}public void setNo(int no
) {this.no
= no
;}public String getName() {return name
;}public void setName(String name
) {this.name
= name
;}public HeroNode getLeft() {return left
;}public void setLeft(HeroNode left
) {this.left
= left
;}public HeroNode getRight() {return right
;}public void setRight(HeroNode right
) {this.right
= right
;}@Overridepublic String toString() {return "HeroNode [no=" + no
+ ", name=" + name
+ "]";}public void preOrder() {System.out
.println(this); if(this.left
!= null) {this.left
.preOrder();}if(this.right
!= null) {this.right
.preOrder();}}public void infixOrder() {if(this.left
!= null) {this.left
.infixOrder();}System.out
.println(this);if(this.right
!= null) {this.right
.infixOrder();}}public void postOrder() {if(this.left
!= null) {this.left
.postOrder();}if(this.right
!= null) {this.right
.postOrder();}System.out
.println(this);}}
class BinaryTree {private HeroNode root
;public void setRoot(HeroNode root
) {this.root
= root
;}public void preOrder() {if(this.root
!= null) {this.root
.preOrder();}else {System.out
.println("二叉樹為空,無法遍歷");}}public void infixOrder() {if(this.root
!= null) {this.root
.infixOrder();}else {System.out
.println("二叉樹為空,無法遍歷");}}public void postOrder() {if(this.root
!= null) {this.root
.postOrder();}else {System.out
.println("二叉樹為空,無法遍歷");}}}
public class BinaryTreeDemo {public static void main(String[] args
) {BinaryTree binaryTree
= new BinaryTree();HeroNode root
= new HeroNode(1, "宋江");HeroNode node2
= new HeroNode(2, "吳用");HeroNode node3
= new HeroNode(3, "盧俊義");HeroNode node4
= new HeroNode(4, "林沖");HeroNode node5
= new HeroNode(5, "關勝");root
.setLeft(node2
);root
.setRight(node3
);node3
.setRight(node4
);node3
.setLeft(node5
);binaryTree
.setRoot(root
);System.out
.println("前序遍歷"); binaryTree
.preOrder();System.out
.println("中序遍歷");binaryTree
.infixOrder(); System.out
.println("后序遍歷");binaryTree
.postOrder(); }}
測試結果:
前序遍歷
HeroNode [no
=1, name
=宋江
]
HeroNode [no
=2, name
=吳用
]
HeroNode [no
=3, name
=盧俊義
]
HeroNode [no
=5, name
=關勝
]
HeroNode [no
=4, name
=林沖
]
中序遍歷
HeroNode [no
=2, name
=吳用
]
HeroNode [no
=1, name
=宋江
]
HeroNode [no
=5, name
=關勝
]
HeroNode [no
=3, name
=盧俊義
]
HeroNode [no
=4, name
=林沖
]
后序遍歷
HeroNode [no
=2, name
=吳用
]
HeroNode [no
=5, name
=關勝
]
HeroNode [no
=4, name
=林沖
]
HeroNode [no
=3, name
=盧俊義
]
HeroNode [no
=1, name
=宋江
]
二叉樹查找結點
前面我們實現了,二叉樹的遍歷,分別有三種方式,有了遍歷,我們就可以實現查找,所以對應的查找方式也有三種:前序遍歷查找、中序遍歷查找、后序遍歷查找。
我們還是在Node中實現三種方法,并在二叉樹中暴露方法
class HeroNode {private int no
;private String name
;private HeroNode left
; private HeroNode right
; public HeroNode(int no
, String name
) {this.no
= no
;this.name
= name
;}public int getNo() {return no
;}public void setNo(int no
) {this.no
= no
;}public String getName() {return name
;}public void setName(String name
) {this.name
= name
;}public HeroNode getLeft() {return left
;}public void setLeft(HeroNode left
) {this.left
= left
;}public HeroNode getRight() {return right
;}public void setRight(HeroNode right
) {this.right
= right
;}@Overridepublic String toString() {return "HeroNode [no=" + no
+ ", name=" + name
+ "]";}public void infixOrder() {if(this.left
!= null) {this.left
.infixOrder();}System.out
.println(this);if(this.right
!= null) {this.right
.infixOrder();}}public void postOrder() {if(this.left
!= null) {this.left
.postOrder();}if(this.right
!= null) {this.right
.postOrder();}System.out
.println(this);}public HeroNode preOrderSearch(int no
) {System.out
.println("進入前序遍歷");if(this.no
== no
) {return this;}HeroNode resNode
= null;if(this.left
!= null) {resNode
= this.left
.preOrderSearch(no
);}if(resNode
!= null) {return resNode
;}if(this.right
!= null) {resNode
= this.right
.preOrderSearch(no
);}return resNode
;}public HeroNode infixOrderSearch(int no
) {HeroNode resNode
= null;if(this.left
!= null) {resNode
= this.left
.infixOrderSearch(no
);}if(resNode
!= null) {return resNode
;}System.out
.println("進入中序查找");if(this.no
== no
) {return this;}if(this.right
!= null) {resNode
= this.right
.infixOrderSearch(no
);}return resNode
;}public HeroNode postOrderSearch(int no
) {HeroNode resNode
= null;if(this.left
!= null) {resNode
= this.left
.postOrderSearch(no
);}if(resNode
!= null) {return resNode
;}if(this.right
!= null) {resNode
= this.right
.postOrderSearch(no
);}if(resNode
!= null) {return resNode
;}System.out
.println("進入后序查找");if(this.no
== no
) {return this;}return resNode
;}}
class BinaryTree {private HeroNode root
;public void setRoot(HeroNode root
) {this.root
= root
;}public void preOrder() {if(this.root
!= null) {this.root
.preOrder();}else {System.out
.println("二叉樹為空,無法遍歷");}}public void infixOrder() {if(this.root
!= null) {this.root
.infixOrder();}else {System.out
.println("二叉樹為空,無法遍歷");}}public void postOrder() {if(this.root
!= null) {this.root
.postOrder();}else {System.out
.println("二叉樹為空,無法遍歷");}}public HeroNode preOrderSearch(int no
) {if(root
!= null) {return root
.preOrderSearch(no
);} else {return null;}}public HeroNode infixOrderSearch(int no
) {if(root
!= null) {return root
.infixOrderSearch(no
);}else {return null;}}public HeroNode postOrderSearch(int no
) {if(root
!= null) {return this.root
.postOrderSearch(no
);}else {return null;}}
}
測試
public class BinaryTreeDemo {public static void main(String[] args
) {BinaryTree binaryTree
= new BinaryTree();HeroNode root
= new HeroNode(1, "宋江");HeroNode node2
= new HeroNode(2, "吳用");HeroNode node3
= new HeroNode(3, "盧俊義");HeroNode node4
= new HeroNode(4, "林沖");HeroNode node5
= new HeroNode(5, "關勝");root
.setLeft(node2
);root
.setRight(node3
);node3
.setRight(node4
);node3
.setLeft(node5
);binaryTree
.setRoot(root
);System.out
.println("前序遍歷方式~~~");HeroNode resNode
= binaryTree
.preOrderSearch(5);if (resNode
!= null) {System.out
.printf("找到了,信息為 no=%d name=%s", resNode
.getNo(), resNode
.getName());} else {System.out
.printf("沒有找到 no = %d 的英雄", 5);}System.out
.println("中序遍歷方式~~~");HeroNode resNode
= binaryTree
.infixOrderSearch(5);if (resNode
!= null) {System.out
.printf("找到了,信息為 no=%d name=%s", resNode
.getNo(), resNode
.getName());} else {System.out
.printf("沒有找到 no = %d 的英雄", 5);}System.out
.println("后序遍歷方式~~~");HeroNode resNode
= binaryTree
.postOrderSearch(5);if (resNode
!= null) {System.out
.printf("找到了,信息為 no=%d name=%s", resNode
.getNo(), resNode
.getName());} else {System.out
.printf("沒有找到 no = %d 的英雄", 5);}}}
前序遍歷方式
~~~
進入前序遍歷
進入前序遍歷
進入前序遍歷
進入前序遍歷
找到了,信息為 no
=5 name
=關勝中序遍歷方式
~~~
進入中序查找
進入中序查找
進入中序查找
找到了,信息為 no
=5 name
=關勝后序遍歷方式
~~~
進入后序查找
進入后序查找
找到了,信息為 no
=5 name
=關勝
這并不能說明哪種遍歷方式更好
二叉樹-刪除節點
要求
- 如果刪除的節點是葉子節點,則刪除該節點
- 如果刪除的節點是非葉子節點,則刪除該子樹.
- 測試,刪除掉 5號葉子節點 和 3號子樹.
package com.atguigu.tree;public class BinaryTreeDemo {public static void main(String[] args
) {BinaryTree binaryTree
= new BinaryTree();HeroNode root
= new HeroNode(1, "宋江");HeroNode node2
= new HeroNode(2, "吳用");HeroNode node3
= new HeroNode(3, "盧俊義");HeroNode node4
= new HeroNode(4, "林沖");HeroNode node5
= new HeroNode(5, "關勝");root
.setLeft(node2
);root
.setRight(node3
);node3
.setRight(node4
);node3
.setLeft(node5
);binaryTree
.setRoot(root
);System.out
.println("刪除前,前序遍歷");binaryTree
.preOrder(); binaryTree
.delNode(5);System.out
.println("刪除后,前序遍歷");binaryTree
.preOrder(); }}
class BinaryTree {private HeroNode root
;public void setRoot(HeroNode root
) {this.root
= root
;}public void delNode(int no
) {if(root
!= null) {if(root
.getNo() == no
) {root
= null;} else {root
.delNode(no
);}}else{System.out
.println("空樹,不能刪除~");}}public void preOrder() {if(this.root
!= null) {this.root
.preOrder();}else {System.out
.println("二叉樹為空,無法遍歷");}}public void infixOrder() {if(this.root
!= null) {this.root
.infixOrder();}else {System.out
.println("二叉樹為空,無法遍歷");}}public void postOrder() {if(this.root
!= null) {this.root
.postOrder();}else {System.out
.println("二叉樹為空,無法遍歷");}}public HeroNode preOrderSearch(int no
) {if(root
!= null) {return root
.preOrderSearch(no
);} else {return null;}}public HeroNode infixOrderSearch(int no
) {if(root
!= null) {return root
.infixOrderSearch(no
);}else {return null;}}public HeroNode postOrderSearch(int no
) {if(root
!= null) {return this.root
.postOrderSearch(no
);}else {return null;}}
}
class HeroNode {private int no
;private String name
;private HeroNode left
; private HeroNode right
; public HeroNode(int no
, String name
) {this.no
= no
;this.name
= name
;}public int getNo() {return no
;}public void setNo(int no
) {this.no
= no
;}public String getName() {return name
;}public void setName(String name
) {this.name
= name
;}public HeroNode getLeft() {return left
;}public void setLeft(HeroNode left
) {this.left
= left
;}public HeroNode getRight() {return right
;}public void setRight(HeroNode right
) {this.right
= right
;}@Overridepublic String toString() {return "HeroNode [no=" + no
+ ", name=" + name
+ "]";}public void delNode(int no
) {if(this.left
!= null && this.left
.no
== no
) {this.left
= null;return;}if(this.right
!= null && this.right
.no
== no
) {this.right
= null;return;}if(this.left
!= null) {this.left
.delNode(no
);}if(this.right
!= null) {this.right
.delNode(no
);}}public void preOrder() {System.out
.println(this); if(this.left
!= null) {this.left
.preOrder();}if(this.right
!= null) {this.right
.preOrder();}}public void infixOrder() {if(this.left
!= null) {this.left
.infixOrder();}System.out
.println(this);if(this.right
!= null) {this.right
.infixOrder();}}public void postOrder() {if(this.left
!= null) {this.left
.postOrder();}if(this.right
!= null) {this.right
.postOrder();}System.out
.println(this);}public HeroNode preOrderSearch(int no
) {System.out
.println("進入前序遍歷");if(this.no
== no
) {return this;}HeroNode resNode
= null;if(this.left
!= null) {resNode
= this.left
.preOrderSearch(no
);}if(resNode
!= null) {return resNode
;}if(this.right
!= null) {resNode
= this.right
.preOrderSearch(no
);}return resNode
;}public HeroNode infixOrderSearch(int no
) {HeroNode resNode
= null;if(this.left
!= null) {resNode
= this.left
.infixOrderSearch(no
);}if(resNode
!= null) {return resNode
;}System.out
.println("進入中序查找");if(this.no
== no
) {return this;}if(this.right
!= null) {resNode
= this.right
.infixOrderSearch(no
);}return resNode
;}public HeroNode postOrderSearch(int no
) {HeroNode resNode
= null;if(this.left
!= null) {resNode
= this.left
.postOrderSearch(no
);}if(resNode
!= null) {return resNode
;}if(this.right
!= null) {resNode
= this.right
.postOrderSearch(no
);}if(resNode
!= null) {return resNode
;}System.out
.println("進入后序查找");if(this.no
== no
) {return this;}return resNode
;}}
總結
以上是生活随笔為你收集整理的二叉树的前序遍历、中序遍历、后序遍历的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。