树的定义
树是由结点和边组成的,不存在环的一种数据结构
树的层次关系和节点的称呼:
- A 结点是 B 结点和 C 结点的上级,则 A 就是 B 和 C 的父结点,B 和 C 是 A 的子结点。
- B 和 C 同时是 A 的“孩子”,则可以称 B 和 C 互为兄弟结点。
- A 没有父结点,则可以称 A 为根结点。
- G、H、I、F 结点都没有子结点,则称 G、H、I、F 为叶子结
这是一颗深度为4的树
二叉树的定义
- 二叉树的特殊类型
- 满二叉树,定义为除了叶子结点外,所有结点都有 2 个子结点。
- 完全二叉树,定义为除了最后一层以外,其他层的结点个数都达到最大,并且最后一层的叶子结点都靠左排列。
- 存储二叉树
链式存储法:就是像链表一样,每个结点有三个字段,一个存储数据,另外两个分别存放指向左右子结点的指针
-
顺序存储法,就是按照规律把结点存放在数组里,如下图所示,为了方便计算,我们会约定把根结点放在下标为 1 的位置。随后,B 结点存放在下标为 2 的位置,C 结点存放在下标为 3 的位置,依次类推。
(根据这种存储方法,我们可以发现如果结点 X 的下标为 i,那么 X 的左子结点总是存放在 2 * i 的位置,X 的右子结点总是存放在 2 * i + 1 的位置。)
-
树的基本操作
-
前序遍历,对树中的任意结点来说,先打印这个结点,然后前序遍历它的左子树,最后前序遍历它的右子树。
-
中序遍历,对树中的任意结点来说,先中序遍历它的左子树,然后打印这个结点,最后中序遍历它的右子树。
-
后序遍历,对树中的任意结点来说,先后序遍历它的左子树,然后后序遍历它的右子树,最后打印它本身。
二叉树代码实现过程:
package com.bai.webflux.webfluxdemo.test;
public class Node {
private int value; //节点的值
private Node left; //此节点的左子节点,数据类型为Node
private Node right; //此节点的右子节点,数据类型为Node
public int getValue() {
return value;
}
public Node getLeft() {
return left;
}
public Node getRight() {
return right;
}
public Node(int value, Node left, Node right) {
this.value = value;
this.left = left;
this.right = right;
}
public String toString() { //自定义的toString方法,为了方便之后的输出
return this.value+" ";
}
}
package com.bai.webflux.webfluxdemo.test;
public class StringTest {
public static void main(String[] args) {
Node D = new Node(4, null, null);
Node E = new Node(5, null, null);
Node H = new Node(6, null, null);
Node B = new Node(2, D, E);
Node C = new Node(3, null, H);
Node A = new Node(1, B, C);//A为根节点
System.out.print("先序遍历:");
preOrderTraverse(A);
System.out.print("\n中序遍历:");
inOrderTraverse(A);
System.out.print("\n后续遍历:");
postOrderTraverse(A);
}
// 先序遍历
public static void preOrderTraverse(Node node) {
if (node == null)
return;
System.out.print(node.getValue() + " ");
preOrderTraverse(node.getLeft());
preOrderTraverse(node.getRight());
}
// 中序遍历
public static void inOrderTraverse(Node node) {
if (node == null)
return;
inOrderTraverse(node.getLeft());
System.out.print(node.getValue() + " ");
inOrderTraverse(node.getRight());
}
// 后序遍历
public static void postOrderTraverse(Node node) {
if (node == null)
return;
postOrderTraverse(node.getLeft());
postOrderTraverse(node.getRight());
System.out.print(node.getValue() + " ");
}
}
输出:
先序遍历:1 2 4 5 3 6
中序遍历:4 2 5 1 3 6
后续遍历:4 5 2 6 3 1
例子:按照层次顺序遍历并打印这棵树
package com.bai.webflux.webfluxdemo.test;
import java.util.LinkedList;
public class StringTest {
public static void main(String[] args) {
Node D = new Node(4, null, null);
Node E = new Node(5, null, null);
Node H = new Node(6, null, null);
Node B = new Node(2, D, E);
Node C = new Node(3, null, H);
Node A = new Node(1, B, C);//A为根节点
levelTraverse(A);
}
public static void levelTraverse(Node root) {
if (root == null) {
return;
}
//队列具有先进先出的特性
LinkedList<Node> queue = new LinkedList<Node>();
Node current = null;
queue.offer(root); // 根节点入队
while (!queue.isEmpty()) { // 只要队列中有元素,就可以一直执行,非常巧妙地利用了队列的特性
current = queue.poll(); // 出队队头元素
System.out.print("-->" + current.getValue());
// 左子树不为空,入队
if (current.getLeft() != null)
queue.offer(current.getLeft());
// 右子树不为空,入队
if (current.getRight() != null)
queue.offer(current.getRight());
}
}
}
输出:-->1-->2-->3-->4-->5-->6