二叉树是一种非常重要的数据结构,其在查找、排序等领域有着非常重要的应用。本文简单介绍一些关于二叉树的基本概念,并给出几种二叉树的基本遍历方法。全文代码为Java语言实现。
二叉树的基本概念
1. 二叉树的定义
定义: 二叉树是n(n >= 0)个节点所构成的集合,n=0为空树,n>0是非空树。
- 有且仅有一个根节点
- 二叉树的度为小于等于2,即一个父节点最多只会有两个子节点
- 二叉树天生具有递归的特性
- 二叉树的子树有左右之分,其次序不能颠倒
2. 二叉树的性质
- 二叉树的第i层上最多有 2^(i-1) 个节点
- 深度为k的二叉树最多有 2^k - 1 个节点
二叉树的两种特殊形态:
- 满二叉树
特点: 深度为k且含有2^k - 1 个节点的树
- 完全二叉树
特性:具有n个节点的完全二叉树的深度为 |log2N| + 1
二叉树的构造与遍历
1. 二叉树的构造
在Java中,一个节点可以用一个类来描述,其三个成员变量分别为:数据域(value)、指向左子树节点的引用(left)、指向右子树节点的引用(right)
构造节点的代码实现:
/**
* 二叉树节点
*/
private static class TreeNode {
// 数据域
private String value;
// 指向左子树的引用
private TreeNode left;
// 指向右子树的引用
private TreeNode right;
public TreeNode(String value, TreeNode left, TreeNode right) {
this.value = value;
this.left = left;
this.right = right;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public TreeNode getLeft() {
return left;
}
public void setLeft(TreeNode left) {
this.left = left;
}
public TreeNode getRight() {
return right;
}
public void setRight(TreeNode right) {
this.right = right;
}
}
2. 二叉树的遍历
二叉树遍历的三种方式如下:
(1) 先序遍历:根节点->左子树->右子树
下面是两种实现方式:递归实现和非递归实现
/**
* 递归实现 先序遍历:根节点->左子树->右子树
* 1. 访问根节点
* 2. 先序遍历左子树
* 3. 先序遍历右子树
*/
private void preOrderR(TreeNode node) {
if (node != null) {
// 1. 访问根节点
System.out.print(node.getValue() + " ");
// 2. 先序遍历左子树
preOrderR(node.getLeft());
// 3. 先序遍历右子树
preOrderR(node.getRight());
}
}
/**
* 非递归实现 先序遍历
*/
private void preOrder() {
Stack<TreeNode> stack = new Stack<TreeNode>();
stack.push(root);
TreeNode current = null;
while (!stack.isEmpty()) {
current = stack.pop();
System.out.print(current.getValue() + " ");
if (current.getRight() != null) {
stack.push(current.getRight());
}
if (current.getLeft() != null) {
stack.push(current.getLeft());
}
}
System.out.println();
}
(2) 中序遍历:左子树->根节点->右子树
下面是两种实现方式:递归实现和非递归实现
/**
* 递归实现 中序遍历:左子树->根节点->右子树
* 1. 中序遍历左子树
* 2. 访问根节点
* 3. 中序遍历右子树
*/
private void inOrderR(TreeNode node) {
if (node != null) {
// 1. 中序遍历左子树
inOrderR(node.getLeft());
// 2. 访问根节点
System.out.print(node.getValue() + " ");
// 3. 中序遍历右子树
inOrderR(node.getRight());
}
}
/**
* 非递归实现 中序遍历
*/
private void inOrder() {
Stack<TreeNode> stack = new Stack<TreeNode>();
TreeNode current = root;
while (current != null || !stack.isEmpty()) {
while (current != null) {
stack.push(current);
current = current.getLeft();
}
if (!stack.isEmpty()) {
current = stack.pop();
System.out.print(current.getValue() + " ");
current = current.getRight();
}
}
System.out.println();
}
(3) 后续遍历:左子树->右子树->根节点
下面是两种实现方式:递归实现和非递归实现
/**
* 递归实现 后序遍历:左子树->右子树->根节点
* 1. 后续遍历左子树
* 2. 后续遍历右子树
* 3. 访问根节点
*/
private void lastOrderR(TreeNode node) {
if (node != null) {
// 1. 后序遍历左子树
lastOrderR(node.getLeft());
// 2. 后序遍历右子树
lastOrderR(node.getRight());
// 3. 访问根节点
System.out.print(node.getValue() + " ");
}
}
/**
* 非递归实现 后续遍历
*/
private void lastOrder() {
TreeNode rNode = null;
TreeNode current = root;
Stack<TreeNode> stack = new Stack<TreeNode>();
while (current != null || !stack.isEmpty()) {
while (current != null) {
stack.push(current);
current = current.getLeft();
}
current = stack.pop();
while (current != null && (current.getRight()) == null || current.getRight() == rNode) {
System.out.print(current.getValue() + " ");
rNode = current;
if (stack.isEmpty()) {
System.out.println();
return;
}
current = stack.pop();
}
stack.push(current);
current = current.getRight();
}
}
(4) 验证结果
下面是任意给出的一棵二叉树:
验证上面的三种遍历方式:
public class ConstructBinaryTree {
// 根节点
private TreeNode root;
public ConstructBinaryTree(TreeNode root) {
this.root = root;
}
public TreeNode getRoot() {
return root;
}
public void setRoot(TreeNode root) {
this.root = root;
}
public static void main(String[] args) {
// 第三层节点
TreeNode l3_1 = new TreeNode("F", null, null);
TreeNode l3_2 = new TreeNode("G", null, null);
TreeNode r3 = new TreeNode("H", null, null);
// 第二层节点
TreeNode l2 = new TreeNode("E", l3_2, r3);
TreeNode r2 = new TreeNode("D", l3_1, null);
// 第一层节点
TreeNode l1 = new TreeNode("B", null, r2);
TreeNode r1 = new TreeNode("C", l2, null);
TreeNode root = new TreeNode("A", l1, r1);
ConstructBinaryTree cbt = new ConstructBinaryTree(root);
System.out.println("递归 先序遍历:");
cbt.preOrderR(cbt.getRoot());
System.out.println("\n非递归 先序遍历:");
cbt.preOrder();
System.out.println("\n递归 中序遍历:");
cbt.inOrderR(cbt.getRoot());
System.out.println("\n非递归 中序遍历:");
cbt.inOrder();
System.out.println("\n递归 后序遍历:");
cbt.lastOrderR(cbt.getRoot());
System.out.println("\n非递归 后序遍历:");
cbt.lastOrder();
}
}
结果如下:
递归 先序遍历:
A B D F C E G H
非递归 先序遍历:
A B D F C E G H
递归 中序遍历:
B F D A G E H C
非递归 中序遍历:
B F D A G E H C
递归 后序遍历:
F D B G H E C A
非递归 后序遍历:
F D B G H E C A