二叉樹的遍歷
二叉樹遍歷的經典方法有四種,前序遍歷、中序遍歷、後序遍歷和層次遍歷。
其中,前、中、後序,表示的是節點與它的左右子樹節點遍歷打印的先後順序。
前序遍歷是指,對於樹中的任意節點來說,先打印這個節點,然後再打印它的左子樹,最後打印它的右子樹。
中序遍歷是指,對於樹中的任意節點來說,先打印它的左子樹,然後再打印它本身,最後打印它的右子樹。
後序遍歷是指,對於樹中的任意節點來說,先打印它的左子樹,然後再打印它的右子樹,最後打印這個節點本身。
前中後序是DFS(深度優先算法)的思想
實際上,二叉樹的前、中、後序遍歷就是一個遞歸的過程。
前序遍歷,其實就是先打印根節點,然後再遞歸地打印左子樹,最後遞歸地打印右子樹。
前序遍歷的遞推公式:
preOrder(r) = print r->preOrder(r.left)->preOrder(r.right)
中序遍歷的遞推公式:
inOrder(r) = inOrder(r.left)->print r->inOrder(r.right)
後序遍歷的遞推公式:
postOrder(r) = postOrder(r.left)->postOrder(r.right)->print r
遞歸實現
/**
* 先序遍歷
*/
public static void preOrder(Node root) {
if (root == null) {
return;
}
System.out.print(root.value + " -> ");
preOrder(root.left);
preOrder(root.right);
}
/**
* 中序遍歷
*/
public static void inOrder(Node root) {
if (root == null) {
return;
}
inOrder(root.left);
System.out.print(root.value + " -> ");
inOrder(root.right);
}
/**
* 後序遍歷
*/
public static void postOrder(Node root) {
if (root == null) {
return;
}
postOrder(root.left);
postOrder(root.right);
System.out.print(root.value + " -> ");
}
非遞歸實現
遞歸本身是藉助棧實現的,所以非遞歸的實現也需要棧來實現,本質上實際變成了我們“手動遞歸”
/**
* 前序遍歷
*/
public static void preOrder2(Node root) {
if (root == null) {
return;
}
Stack<Node> s = new Stack<>();
s.push(root);
Node curNode;
while (!s.isEmpty()) {
curNode = s.pop();
System.out.print(curNode.data + "->");
// 棧先進後出,所以先加入右側節點,這樣輸出的時候,先輸出左側節點
if (curNode.right != null) {
s.push(curNode.right);
}
if (curNode.left != null) {
s.push(curNode.left);
}
}
}
/**
* 中序遍歷
*/
public static void inOrder2(Node root) {
if (root == null) {
return;
}
Stack<Node> s = new Stack<>();
Node curNode = root;
while (!s.isEmpty() || curNode != null) {
// 入棧所有左節點並輸出左節點
while (curNode != null) {
s.push(curNode);
curNode = curNode.left;
}
// 彈出左節點
curNode = s.pop();
System.out.print(curNode.data + "->");
// 彈出後,指向當前節點的右節點
curNode = curNode.right;
}
}
/**
* 後序遍歷
*/
public static void postOrder2(Node root) {
if (root == null) {
return;
}
Stack<Node> s1 = new Stack<>();
Stack<Node> s2 = new Stack<>();
s1.push(root);
Node curNode;
while (!s1.isEmpty()) {
curNode = s1.pop();
// 中、右、左順序壓入棧中
s2.push(curNode);
// 壓入s1爲先左後右,保證中、右、左順序壓入s2中
if (curNode.left != null) {
s1.push(curNode.left);
}
if (curNode.right != null) {
s1.push(curNode.right);
}
}
while (!s2.isEmpty()) {
System.out.print(s2.pop().data + "->");
}
}
層次遍歷
層次遍歷是BFS(廣度優先算法)的思想。
一般藉助於隊列來實現二叉樹的層次遍歷。
層次遍歷的步驟是:
1.對於不爲空的結點,先把該結點加入到隊列中
2.從隊中拿出結點,如果該結點的左孩子不爲空,就分別把左孩子加入到隊列中,否則什麼都不做。右孩子同理
3.重複以上操作直到隊列爲空,層次遍歷結束
public static void LevelTraversal(Node root) {
if (root == null) {
return;
}
Queue<Node> queue = new LinkedList<Node>();
Node curNode = null;
queue.offer(root);//將根節點入隊
while (!queue.isEmpty()) {
curNode = queue.poll();//出隊隊頭元素並訪問
System.out.print(curNode.data + "->");
if (curNode.left != null)//如果當前節點的左節點不爲空入隊
{
queue.offer(curNode.left);
}
if (curNode.right != null)//如果當前節點的右節點不爲空,把右節點入隊
{
queue.offer(curNode.right);
}
}
}