樹的遍歷
近期參加復旦互聯網協會的刷題營,所以我勉勉強強又開始做題啦。現在變得更務實啦,要想提升能力,超過別人就是要依靠一項項的指標的勝利,這樣的評價是更加客觀的。想要提升能力,一方面要靠平時的積累,另外一方面也要依靠瓶頸期的奮力一搏。當然,我的意思是更加側重前者的。話不多說啦,開始今天的話題——樹的遍歷。如果用遞歸的方法是非常簡單,也是非常推薦的。但是,用迭代的方法也不難!!!所以我決定在這裏探討一下。
LeetCode題目
中序遍歷 ,前序遍歷 和 後序遍歷 。當然,我知道有的朋友,就是喜歡野蠻自己的體魄,那你可以試一試,從中序與後序遍歷序列構造二叉樹 , 從前序與中序遍歷序列構造二叉樹 以及 根據前序和後序遍歷構造二叉樹。 保證你可以受到全身心的虐待。
各種遍歷——遞歸實現
有基礎的同學,跳過本節。
首先是TreeNode結構。
public class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x; }
}
三種遍歷的區別在於,什麼時候訪問root的值。下面是中序遍歷,返回按序排序的值。
class Solution {
List<Integer> list = new LinkedList<>();
public List<Integer> inorderTraversal(TreeNode root) {
add(root);
return list;
}
private void add(TreeNode root) {
if (root == null) return;
add(root.left);
list.add(root.val);
add(root.right);
}
}
之後,是前序遍歷,先訪問root父節點。此後,再訪問左子樹。
class Solution {
List<Integer> list = new LinkedList<>();
public List<Integer> inorderTraversal(TreeNode root) {
add(root);
return list;
}
private void add(TreeNode root) {
if (root == null) return;
list.add(root.val);
add(root.left);
add(root.right);
}
}
後序遍歷也很簡單,就是最後訪問父節點。
class Solution {
List<Integer> list = new LinkedList<>();
public List<Integer> postorderTraversal(TreeNode root) {
add(root);
return list;
}
private void add(TreeNode root) {
if (root == null) return;
add(root.left);
add(root.right);
list.add(root.val);
}
}
各種遍歷的原理圖
相信閱讀了上面的內容,大家都產生了一種樹的遍歷很簡單的錯覺。然而,真實的情況是確實不難。哈哈,接下來講重點啦!
首先是中序遍歷的遍歷順序圖。引用LeetCode的說法,Left -> Node -> Right。只有先訪問完左子樹,才能返回訪問中間節點的元素,再訪問右子樹。順序按照1,2,3,4,...,7
接下來,大家一定好奇前序遍歷的圖。從1開始,到15. 增加箭頭,也許會更加清楚一點,按照LeetCode的說法,Top -> Bottom, Left -> Right。
然後,是後序遍歷。同樣是從1開始。加上標線之後,或許更加清楚。按照LeetCode的說法,Bottom -> Top, Left -> Right。
各種遍歷——迭代實現
中序遍歷
主要通過Stack實現。
前序遍歷
還是和之前的代碼一樣,只不過訪問元素的順序變了。
後序遍歷
同樣用Stack,但是,List用LinkedList,添加的時候用addFirst方法。
後序遍歷,在將中序表達式,轉化爲逆波蘭式的時候可以派上用場。
先序遍歷,可以在列出目錄中的所有文件的時候使用——先列出當前文件夾的所有文件。
關於各種遍歷的用途,參考了這篇文章: https://blog.csdn.net/qq_31929931/article/details/77255658