前言
二叉樹的遍歷有前序遍歷、中序遍歷、後續遍歷、層序遍歷。然後我們分別實現一下各種遍歷的遞歸與非遞歸的方式,樹節點定義如下:
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x; }
}
前序遍歷
前序遍歷是指我們的二叉樹先遍歷root節點,然後遍歷左節點,最後是右節點
遞歸
public void preOrder(TreeNode root){
if (root == null){
return;
}
//輸出當前節點的值
System.out.println(root.val);
//遍歷做子樹
preOrder(root.left);
//遍歷右子樹
preOrder(root.right);
}
非遞歸
public void preOrder(TreeNode root){
if (root == null){
return;
}
//藉助棧先進後出的特性,先將root.right存入,在存入root.left
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while (!stack.isEmpty()){
TreeNode node = stack.pop();
System.out.println(node.val);
if (node.right != null){
stack.push(node.right);
}
if (node.left != null){
stack.push(node.left);
}
}
}
中序遍歷
遞歸
public void midOrder(TreeNode root){
if (root == null){
return;
}
//遍歷做子樹
preOrder(root.left);
//輸出當前節點的值
System.out.println(root.val);
//遍歷右子樹
preOrder(root.right);
}
非遞歸
public void midOrder(TreeNode root){
if (root == null){
return;
}
Stack<TreeNode> stack = new Stack<>();
do {
//如果左節點一直有,一直壓棧
while (root != null){
stack.push(root);
root = root.left;
}
//出棧,判斷是否有右孩子,如果有,就要繼續壓棧
TreeNode node = stack.pop();
System.out.println(node.val);
if (node.right != null){
root = node.right;
}
}while (root!= null || !stack.isEmpty());
}
後序遍歷
遞歸
public void afterOrder(TreeNode root){
if (root == null){
return;
}
//遍歷做子樹
preOrder(root.left);
//遍歷右子樹
preOrder(root.right);
//輸出當前節點的值
System.out.println(root.val);
}
非遞歸
public void afterOrder(TreeNode root){
if (root == null){
return;
}
//藉助兩個棧來實現,因爲要先遍歷右孩子才能root節點,所以root節點要在s2的最底部
Stack<TreeNode> s1 = new Stack<>();
Stack<TreeNode> s2 = new Stack<>();
s1.push(root);
while (!s1.isEmpty()){
TreeNode node = s1.pop();
if (node.left != null){
s1.push(node.left);
}
if (node.right != null){
s1.push(node.right);
}
s2.push(node);
}
while (!s2.isEmpty()){
System.out.println(s2.pop().val);
}
}
層序遍歷
層序遍歷是指將二叉樹的節點一層一層的遍歷出來,這裏我假設將節點存入list,採用BFS的方式遍歷節點。
public List<List<Integer>> levelOrder(TreeNode root) {
//存訪每一層的結果
List<List<Integer>> lists = new ArrayList<>();
if (root == null){
return lists;
}
//藉助隊列存放每一層的節點
Queue<TreeNode> queue = new LinkedBlockingQueue<>();
queue.add(root);
while (!queue.isEmpty()){
List<Integer> list = new ArrayList<>();
int size = queue.size();
//獲取當前隊列中的所有節點,然後將每個節點的左右孩子放入隊列,以提供下層循環輸出
for (int i = 0; i < size; i++) {
TreeNode node = queue.poll();
list.add(node.val);
if (node.left != null){
queue.add(node.left);
}
if (node.right != null){
queue.add(node.right);
}
}
//每一層的list存入lists
lists.add(list);
}
return lists;
}