二叉樹是每個節點最多只有兩個分支(即不存在分支度大于2的節點)的樹結構。通常分支被稱作“左子樹”或“右子樹”。二叉樹的分支具有左右次序,不能隨意顛倒。
序言
二叉樹的遍歷方式主要有:先序遍歷、中序遍歷、后序遍歷、層次遍歷。先序、中序、后序指的是父節點被訪問的次序。本篇文章將用java代碼實現下圖中的二叉樹的遍歷
數據結構 二叉樹
創建圖中節點
public class TreeNode<T> {
private T data;
private TreeNode left;
private TreeNode right;
}
TreeNode treeNodeA = new TreeNode("A");
TreeNode treeNodeB = new TreeNode("B");
TreeNode treeNodeC = new TreeNode("C");
TreeNode treeNodeD = new TreeNode("D");
TreeNode treeNodeE = new TreeNode("E");
TreeNode treeNodeF = new TreeNode("F");
treeNodeA.setLeft(treeNodeB);
treeNodeA.setRight(treeNodeC);
treeNodeB.setLeft(treeNodeD);
treeNodeB.setRight(treeNodeE);
treeNodeC.setLeft(treeNodeF);
前序遍歷
遍歷思路:在遍歷過程中,父節點先于它的子節點被訪問(父節點 -> 左子樹 -> 右子樹)
- 前序遍歷代碼
private void preOrderTraverse(TreeNode treeNode, VisitListener visitListener) {
if (treeNode == null) {
return;
}
visitListener.visit(treeNode.getData());
preOrderTraverse(treeNode.getLeft(), visitListener);
preOrderTraverse(treeNode.getRight(), visitListener);
}
- 測試代碼
preOrderTraverse(treeNodeA, new VisitListener<String>() {
@Override
public void visit(String treeNodeData) {
Log.d("TAG", treeNodeData);
}
});
- 輸出
2020-05-25 21:32:40.508 16157-16157/? D/TAG: A
2020-05-25 21:32:40.508 16157-16157/? D/TAG: B
2020-05-25 21:32:40.508 16157-16157/? D/TAG: D
2020-05-25 21:32:40.508 16157-16157/? D/TAG: E
2020-05-25 21:32:40.508 16157-16157/? D/TAG: C
2020-05-25 21:32:40.508 16157-16157/? D/TAG: F
中序遍歷
遍歷思路:在遍歷過程中,父節點被訪問的次序位于左右子節點之間( 左子樹 -> 父節點 ->右子樹)
- 中序遍歷代碼
private void infixOrderTraverse(TreeNode treeNode, VisitListener visitListener) {
if (treeNode == null) {
return;
}
infixOrderTraverse(treeNode.getLeft(), visitListener);
visitListener.visit(treeNode.getData());
infixOrderTraverse(treeNode.getRight(), visitListener);
}
- 測試代碼
infixOrderTraverse(treeNodeA, new VisitListener<String>() {
@Override
public void visit(String treeNodeData) {
Log.d("TAG", treeNodeData);
}
});
- 輸出
2020-05-25 21:32:40.508 16157-16157/? D/TAG: D
2020-05-25 21:32:40.508 16157-16157/? D/TAG: B
2020-05-25 21:32:40.508 16157-16157/? D/TAG: E
2020-05-25 21:32:40.508 16157-16157/? D/TAG: A
2020-05-25 21:32:40.508 16157-16157/? D/TAG: F
2020-05-25 21:32:40.508 16157-16157/? D/TAG: C
后序遍歷
遍歷思路:在遍歷過程中,訪問完左右子節點之后再訪問父節點( 左子樹 ->右子樹 -> 父節點)
- 后序遍歷代碼
private void epilogueOrderTraverse(TreeNode treeNode, VisitListener visitListener) {
if (treeNode == null) {
return;
}
epilogueOrderTraverse(treeNode.getLeft(), visitListener);
epilogueOrderTraverse(treeNode.getRight(), visitListener);
visitListener.visit(treeNode.getData());
}
- 測試代碼
epilogueOrderTraverse(treeNodeA, new VisitListener<String>() {
@Override
public void visit(String treeNodeData) {
Log.d("TAG", treeNodeData);
}
});
- 輸出
2020-05-25 21:32:40.508 16157-16157/? D/TAG: D
2020-05-25 21:32:40.508 16157-16157/? D/TAG: E
2020-05-25 21:32:40.508 16157-16157/? D/TAG: B
2020-05-25 21:32:40.508 16157-16157/? D/TAG: F
2020-05-25 21:32:40.508 16157-16157/? D/TAG: C
2020-05-25 21:32:40.508 16157-16157/? D/TAG: A
層序遍歷
遍歷思路:在遍歷過程中,按照從上到下、從左向右的順序訪問二叉樹的每個節點
- 層序遍歷代碼
private void levelOrderTraverse(TreeNode treeNode, VisitListener visitListener) {
if (treeNode == null) {
return;
}
Queue<TreeNode> treeNodeQueue = new ArrayDeque<>();
treeNodeQueue.add(treeNode);
TreeNode currentNode;
while (!treeNodeQueue.isEmpty()) {
currentNode = treeNodeQueue.peek();
visitListener.visit(currentNode.getData());
if (currentNode.getLeft() != null) {
treeNodeQueue.add(currentNode.getLeft());
}
if (currentNode.getRight() != null) {
treeNodeQueue.add(currentNode.getRight());
}
treeNodeQueue.poll();
}
}
- 測試代碼
levelOrderTraverse(treeNodeA, new VisitListener<String>() {
@Override
public void visit(String treeNodeData) {
Log.d("TAG", treeNodeData);
}
});
- 輸出
2020-05-25 21:32:40.508 16157-16157/? D/TAG: A
2020-05-25 21:32:40.508 16157-16157/? D/TAG: B
2020-05-25 21:32:40.508 16157-16157/? D/TAG: C
2020-05-25 21:32:40.508 16157-16157/? D/TAG: D
2020-05-25 21:32:40.508 16157-16157/? D/TAG: E
2020-05-25 21:32:40.508 16157-16157/? D/TAG: F