如何创建一颗二叉树?
- 先创建一个根结点
- 通过这个根结点,创建它的左节点和右节点
- 再为它的左节点和右节点分别创建左节点和右节点
- 依次递归
创建一颗静态的二叉树
就是我们直接创建结点,为结点赋值,然后将结点连接起来,就形成了一颗二叉树
首先,创建一个结点类
- 一个结点的信息包括:结点的值、它的左结点、它的右结点
在结点类中实现两个方法
- 设置左节点:传入一个结点参数,将传入的结点设置为当前结点的左节点
- 设置右节点:传入一个结点参数,将传入的结点设置为当前结点的右节点
package tree;
/**
* 创建一个结点
*/
class Node {
// 结点的权
int value;
// 左结点
Node leftNode;
// 右节点
Node rightNode;
Node(int value) {
this.value = value;
}
// 设置左结点
void setLeftNode(Node leftNode) {
this.leftNode = leftNode;
}
// 设置右节点
void setRightNode(Node rightNode) {
this.rightNode = rightNode;
}
}
然后再创建一颗二叉树,创建过程就是
- 创建一个根结点、一个左节点、一个右节点
- (此时这三个结点除了值不同外,都是一样的)
- 然后将左右结点设置为根结点的左右结点
- (此时已将这三个结点连接起来,形成了一颗二叉树)
package tree;
/**
* 静态创建二叉树
*/
public class StaticBinaryTree {
private void createBinaryTree() {
// 创建一个结点
Node root = new Node(0);
// 创建其它结点
Node left = new Node(1);
Node right = new Node(2);
// 将其设置为根结点的左节点和右节点
root.setLeftNode(left);
root.setRightNode(right);
}
public static void main(String[] args) {
StaticBinaryTree tree = new StaticBinaryTree();
tree.createBinaryTree();
}
}
这样,一颗简单的二叉树就创建好了
它的根结点的值为0,左节点值为1,右节点值为2,每个结点都是我们一个一个创建的,所以才称为静态创建
而我们使用递归的方式,则可实现动态创建二叉树
创建一颗满二叉树
- 根据指定层数,创建一个满二叉树,按层来依次来分配结点的值
- 并实现四种方式遍历二叉树(下面讲解)
同样,还是先创建一个结点类,和上面的一样,创建一次即可
package tree;
/**
* 创建一个结点
*/
class Node {
// 结点的权
int value;
// 左结点
Node leftNode;
// 右节点
Node rightNode;
Node(int value) {
this.value = value;
}
// 设置左结点
void setLeftNode(Node leftNode) {
this.leftNode = leftNode;
}
// 设置右节点
void setRightNode(Node rightNode) {
this.rightNode = rightNode;
}
}
创建一颗满二叉树
- 根据构造方法中传入:根结点和二叉树的深度
- 一个结点的序号为 i ,则它的左节点为(2 * i + 1),右节点为(2 * i + 2)
- 递归创建,即当我们为根结点创建左右结点后,再为分别左右节点再创建左右结点,依次递归,直到指定深度
package tree;
import java.util.LinkedList;
import java.util.Queue;
public class CreateBinaryTree {
private Node root;
private int depth;
// 构造方法,初始化根结点和二叉树的深度
private CreateBinaryTree(Node root, int depth) {
this.root = root;
this.depth = depth;
}
// 递归创建满二叉树
private void fullBinaryTree(int currentDepth, Node root, int index) {
if (currentDepth > depth) {
return;
}
// 创建左节点
Node leftNode = new Node(2 * index + 1);
root.setLeftNode(leftNode);
// 创建右节点
Node rightNode = new Node(2 * index + 2);
root.setRightNode(rightNode);
// 递归,分别以左右结点,再创建
fullBinaryTree(currentDepth + 1, leftNode, 2 * index + 1);
fullBinaryTree(currentDepth + 1, rightNode, 2 * index + 2);
}
// 先序遍历
private void preorderTraversal(Node node) {
if (node == null) {
return;
}
System.out.print(node.value + " ");
preorderTraversal(node.leftNode);
preorderTraversal(node.rightNode);
}
// 中序遍历
private void inorderTraversal(Node node) {
if (node == null) {
return;
}
inorderTraversal(node.leftNode);
System.out.print(node.value + " ");
inorderTraversal(node.rightNode);
}
// 后序遍历
private void postorderTraversal(Node node) {
if (node == null) {
return;
}
postorderTraversal(node.leftNode);
postorderTraversal(node.rightNode);
System.out.print(node.value + " ");
}
// 层次遍历
private void levelTraversal(Node node) {
if (node == null) {
return;
}
Queue<Node> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
Node treeNode = queue.poll();
System.out.print(treeNode.value + " ");
if (treeNode.leftNode != null) {
queue.offer(treeNode.leftNode);
}
if (treeNode.rightNode != null) {
queue.offer(treeNode.rightNode);
}
}
}
public static void main(String[] args) {
// 创建根结点
Node root = new Node(0);
// 初始化
CreateBinaryTree tree = new CreateBinaryTree(root, 3);
// 创建二叉树
tree.fullBinaryTree(0, root, 0);
// 遍历
System.out.print("先序遍历:");
tree.preorderTraversal(root);
System.out.println();
System.out.print("中序遍历:");
tree.inorderTraversal(root);
System.out.println();
System.out.print("后序遍历:");
tree.postorderTraversal(root);
System.out.println();
System.out.print("层次遍历:");
tree.levelTraversal(root);
}
}
上述代码在创建完二叉树之后,以四种遍历方式遍历二叉树,输出结果如下
遍历二叉树
- 就是打印结点的顺序不同
先序遍历:根结点 ---> 左子树 ---> 右子树
中序遍历:左子树 ---> 根结点 ---> 右子树
后序遍历:左子树 ---> 右子树 ---> 根结点
层次遍历:按层数依次遍历每个结点
先序遍历
private void preorderTraversal(Node node) {
if (node == null) {
return;
}
System.out.print(node.value + " ");
preorderTraversal(node.leftNode);
preorderTraversal(node.rightNode);
}
中序遍历
private void inorderTraversal(Node node) {
if (node == null) {
return;
}
inorderTraversal(node.leftNode);
System.out.print(node.value + " ");
inorderTraversal(node.rightNode);
}
后序遍历
private void postorderTraversal(Node node) {
if (node == null) {
return;
}
postorderTraversal(node.leftNode);
postorderTraversal(node.rightNode);
System.out.print(node.value + " ");
}
层次遍历
在此,我们需要一个队列,将当前层的结点存入队列,然后遍历队列中的每个结点
在遍历队列中每个结点的时候,再判断它们的子节点,如果有子节点,则放入队列的末尾,等这一层的结点都遍历完成后,才可遍历它们的子节点,这样既可实现层次遍历
private void levelTraversal(Node node) {
if (node == null) {
return;
}
Queue<Node> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
Node treeNode = queue.poll();
System.out.print(treeNode.value + " ");
if (treeNode.leftNode != null) {
queue.offer(treeNode.leftNode);
}
if (treeNode.rightNode != null) {
queue.offer(treeNode.rightNode);
}
}
}
对比链表和二叉树:链表中的结点只有一个后继结点,而二叉树的结点有两个后继结点(子节点)