二叉樹演算法系列文章
演算法知識梳理(11) - 二叉樹相關演算法第一部分
演算法知識梳理(12) - 二叉樹相關演算法第二部分
演算法知識梳理(13) - 二叉樹相關演算法第三部分
一、概述
在 演算法知識梳理(10) - 二叉查詢樹 中,我們簡要介紹了二叉查詢樹的基本概念、插入及刪除操作,今天這篇文章,以這個為基礎,介紹一下和二叉樹有關的操作,由於篇幅有限,因此分為三篇文章介紹,第一部分包括:
- 遞迴遍歷二叉樹(先序遍歷、中序遍歷、後序遍歷)
- 分層列印二叉樹
- 列印二叉樹的第
n
層 - 統計二叉樹葉結點的個數
- 統計二叉樹的高度
二、程式碼實現
2.1 遞迴遍歷
解決思路
二叉樹的遍歷方式有以下三種:
- 先序遍歷:根結點 -> 左子樹 -> 右子樹
- 中序遍歷:左子樹 -> 根結點 -> 右子樹
- 後序遍歷:左子樹 -> 右子樹 -> 根結點
遞迴的方式比較容易理解,只需要改變函式呼叫和列印元素值語句之間的順序即可,例如先序遍歷,就先列印該結點元素的值,再分別列印左子樹和右子樹即可。
程式碼實現
class Untitled {
static class Tree {
int size;
Node root;
}
static class Node {
Node parent;
Node left;
Node right;
int value;
}
static void insertNode(Tree tree, int value) {
if (tree == null) {
return;
}
Node tNode = tree.root;
//待插入結點的父結點,如果遍歷完為空,說明此時是一個空樹。
Node pNode = null;
//新的結點。
Node nNode = new Node();
nNode.value = value;
while (tNode != null) {
pNode = tNode;
if (tNode.value > value) {
tNode = tNode.left;
} else {
tNode = tNode.right;
}
}
nNode.parent = pNode;
if (pNode == null) {
tree.root = nNode;
} else if (pNode.value > value) {
pNode.left = nNode;
} else {
pNode.right = nNode;
}
tree.size++;
}
static Tree createBinTree(int p[], int len) {
Tree tree = new Tree();
for (int i = 0; i < len; i++) {
int value = p[i];
insertNode(tree, value);
}
return tree;
}
static void printPreOrder(Node node) {
if (node == null) {
return;
}
//先列印根結點。
System.out.println(node.value);
//先遍歷左子樹。
printPreOrder(node.left);
//再遍歷右子樹。
printPreOrder(node.right);
}
static void printInOrder(Node node) {
if (node == null) {
return;
}
printInOrder(node.left);
//遍歷完左子樹後,列印根結點,最後遍歷右子樹。
System.out.println(node.value);
printInOrder(node.right);
}
static void printPostOrder(Node node) {
if (node == null) {
return;
}
//先遍歷右子樹。
printPostOrder(node.right);
//再遍歷左子樹。
printPostOrder(node.left);
//最後列印根結點。
System.out.println(node.value);
}
public static void main(String[] args) {
int p[] = {3, 5, 6, 1, 2, 4};
Tree tree = createBinTree(p, p.length);
System.out.println("- 先序遍歷 - ");
printPreOrder(tree.root);
System.out.println("- 中序遍歷 - ");
printInOrder(tree.root);
System.out.println("- 後序遍歷 - ");
printPostOrder(tree.root);
}
}
複製程式碼
執行結果
- 先序遍歷 -
3
1
2
5
4
6
- 中序遍歷 -
1
2
3
4
5
6
- 後序遍歷 -
6
4
5
2
1
3
複製程式碼
2.2 分層列印二叉樹
解決思路
假設建立了一棵如下的二叉樹,元素3
為第一層,1、5
為第二層,-1、2、4、6
為第三層,要求按照層的順序依次列印出每一層的所有元素。
LinkedList
來進行儲存下一行的元素,並用end
儲存每一行的最後一個元素,遍歷到該元素時列印換行符來實現分層列印。
程式碼實現
import java.util.LinkedList;
public class Untitled {
static class Tree {
int size;
Node root;
}
static class Node {
Node parent;
Node left;
Node right;
int value;
}
static void insertNode(Tree tree, int value) {
if (tree == null) {
return;
}
Node tNode = tree.root;
//待插入結點的父結點,如果遍歷完為空,說明此時是一個空樹。
Node pNode = null;
//新的結點。
Node nNode = new Node();
nNode.value = value;
while (tNode != null) {
pNode = tNode;
if (tNode.value > value) {
tNode = tNode.left;
} else {
tNode = tNode.right;
}
}
nNode.parent = pNode;
if (pNode == null) {
tree.root = nNode;
} else if (pNode.value > value) {
pNode.left = nNode;
} else {
pNode.right = nNode;
}
tree.size++;
}
static Tree createBinTree(int p[], int len) {
Tree tree = new Tree();
for (int i = 0; i < len; i++) {
int value = p[i];
insertNode(tree, value);
}
return tree;
}
static void printTreeLevelOrder(Tree tree) {
if (tree == null || tree.root == null) {
return;
}
Node root = tree.root;
LinkedList<Node> queue = new LinkedList<>();
//先放入根結點。
queue.offer(root);
//對應於下一層的最後一個元素。
Node end = root;
while (!queue.isEmpty()) {
//取出當前佇列中的首結點,並列印它的值。
Node node = queue.getFirst();
System.out.print(String.valueOf(node.value));
//將該結點的左右孩子放入到佇列的尾部。
if (node.left != null) {
queue.offer(node.left);
}
if (node.right != null) {
queue.offer(node.right);
}
//如果當前的結點是該行的尾結點,那麼列印一個換行符,並且將 end 賦值為下一行的尾結點。
if (node == end) {
System.out.print("\n");
end = queue.getLast();
} else {
System.out.print(" ");
}
//將該結點從佇列頭部刪除。
queue.pop();
}
}
public static void main(String[] args) {
int p[] = {3, 5, 6, 1, 2, 4, -1, -3};
Tree tree = createBinTree(p, p.length);
printTreeLevelOrder(tree);
}
}
複製程式碼
執行結果
>> 3
>> 1 5
>> -1 2 4 6
>> -3
複製程式碼
2.3 列印二叉樹的第 n 層
解決思路
列印二叉樹的第n
層和2.2
中是相同的原理,只不過是在遍歷到第n
層時才列印所需的元素。
程式碼實現
import java.util.LinkedList;
public class Untitled {
static class Tree {
int size;
Node root;
}
static class Node {
Node parent;
Node left;
Node right;
int value;
}
static void insertNode(Tree tree, int value) {
if (tree == null) {
return;
}
Node tNode = tree.root;
//待插入結點的父結點,如果遍歷完為空,說明此時是一個空樹。
Node pNode = null;
//新的結點。
Node nNode = new Node();
nNode.value = value;
while (tNode != null) {
pNode = tNode;
if (tNode.value > value) {
tNode = tNode.left;
} else {
tNode = tNode.right;
}
}
nNode.parent = pNode;
if (pNode == null) {
tree.root = nNode;
} else if (pNode.value > value) {
pNode.left = nNode;
} else {
pNode.right = nNode;
}
tree.size++;
}
static Tree createBinTree(int p[], int len) {
Tree tree = new Tree();
for (int i = 0; i < len; i++) {
int value = p[i];
insertNode(tree, value);
}
return tree;
}
static void printTreeKLevel(Tree tree, int k) {
if (tree == null || tree.root == null) {
return;
}
Node root = tree.root;
LinkedList<Node> queue = new LinkedList<>();
//先放入根結點。
queue.offer(root);
//對應於下一層的最後一個元素。
Node end = root;
int curLevel = 1;
while (!queue.isEmpty()) {
//取出當前佇列中的首結點,並列印它的值。
Node node = queue.getFirst();
//如果當前位於第k層,那麼就列印元素。
if (curLevel == k) {
System.out.print(String.valueOf(node.value));
}
//將該結點的左右孩子放入到佇列的尾部。
if (node.left != null) {
queue.offer(node.left);
}
if (node.right != null) {
queue.offer(node.right);
}
if (node == end) {
curLevel++;
//如果大於k層,那麼就跳出迴圈。
if (curLevel > k) {
break;
}
end = queue.getLast();
} else {
System.out.print(" ");
}
//將該結點從佇列頭部刪除。
queue.pop();
}
}
public static void main(String[] args) {
int p[] = {3, 5, 6, 1, 2, 4, -1, -3};
Tree tree = createBinTree(p, p.length);
printTreeKLevel(tree, 3);
}
}
複製程式碼
執行結果
>> -1 2 4 6
複製程式碼
2.4 統計二叉樹的葉結點個數
解決思路
葉結點指的是沒有左右子樹的結點,因此二叉樹的葉結點個數等於它的左右子樹葉結點之和,可以通過遞迴的方法來實現。
程式碼實現
public class Untitled {
static class Tree {
int size;
Node root;
}
static class Node {
Node parent;
Node left;
Node right;
int value;
}
static void insertNode(Tree tree, int value) {
if (tree == null) {
return;
}
Node tNode = tree.root;
//待插入結點的父結點,如果遍歷完為空,說明此時是一個空樹。
Node pNode = null;
//新的結點。
Node nNode = new Node();
nNode.value = value;
while (tNode != null) {
pNode = tNode;
if (tNode.value > value) {
tNode = tNode.left;
} else {
tNode = tNode.right;
}
}
nNode.parent = pNode;
if (pNode == null) {
tree.root = nNode;
} else if (pNode.value > value) {
pNode.left = nNode;
} else {
pNode.right = nNode;
}
tree.size++;
}
static Tree createBinTree(int p[], int len) {
Tree tree = new Tree();
for (int i = 0; i < len; i++) {
int value = p[i];
insertNode(tree, value);
}
return tree;
}
static int getLeafNumber(Node node) {
if (node == null) {
return 0;
}
if (node.left == null && node.right == null) {
return 1;
}
return getLeafNumber(node.left) + getLeafNumber(node.right);
}
public static void main(String[] args) {
int p[] = {3, 5, 6, 1, 2, 4, -1, -3};
Tree tree = createBinTree(p, p.length);
System.out.println("葉結點個數=" + getLeafNumber(tree.root));
}
}
複製程式碼
執行結果
>> 葉結點個數=4
複製程式碼
2.5 統計二叉樹的高度
解決思路
二叉樹的高度 為其根結點到葉結點的最大距離,我們可以先求出它的左右子樹的高度的最大值,再加上1
就可得到以該結點為根結點的二叉樹的高度,同樣可以採用遞迴的方式來實現。
程式碼實現
public class Untitled {
static class Tree {
int size;
Node root;
}
static class Node {
Node parent;
Node left;
Node right;
int value;
}
static void insertNode(Tree tree, int value) {
if (tree == null) {
return;
}
Node tNode = tree.root;
//待插入結點的父結點,如果遍歷完為空,說明此時是一個空樹。
Node pNode = null;
//新的結點。
Node nNode = new Node();
nNode.value = value;
while (tNode != null) {
pNode = tNode;
if (tNode.value > value) {
tNode = tNode.left;
} else {
tNode = tNode.right;
}
}
nNode.parent = pNode;
if (pNode == null) {
tree.root = nNode;
} else if (pNode.value > value) {
pNode.left = nNode;
} else {
pNode.right = nNode;
}
tree.size++;
}
static Tree createBinTree(int p[], int len) {
Tree tree = new Tree();
for (int i = 0; i < len; i++) {
int value = p[i];
insertNode(tree, value);
}
return tree;
}
static int getTreeHeight(Node node) {
if (node == null) {
return 0;
}
int left = getTreeHeight(node.left) + 1;
int right = getTreeHeight(node.right) + 1;
return left > right ? left : right;
}
public static void main(String[] args) {
int p[] = {3, 5, 6, 1, 2, 4, -1, -3};
Tree tree = createBinTree(p, p.length);
System.out.println("二叉樹高度=" + getTreeHeight(tree.root));
}
}
複製程式碼
執行結果
>> 二叉樹高度=4
複製程式碼