二叉树是树这种数据结构的一员,那么为什么要使用树?它有什么优点?
因为树这种数据结构能同时具备数组查找快的优点以及链表插入和删除快的优点。
二叉树的每个节点最多只能有两个子节点,通常叫左子树,和右子树.
先来简单计算一下二叉树
1.怎么计算二叉树上某一层有多少个节点? 通过公式计算得出,第i层上至多有且(i≥1)个节点
以下图为例,假设第3层,计算得出3层有4个节点.
2.怎么通过深度计算二叉树最多有多少个节点? 通过公式计算得出,深度为k且有个结点
以下图为例,假设深度为3,计算得出深度为3的二叉树,最多拥有7个节点
二叉树的形态之一
满二叉树的定义:1.一棵深度为k且有个结点的二叉树称为满二叉树.
2.满二叉树每一层的结点个数都达到了最大值, 即满二叉树的第i层上有个结点 (i≥1).
二叉树的形态之一
完全二叉树定义:如果对满二叉树的结点进行编号, 约定编号从根结点起, 自上而下, 自左而右。则深度为k的, 有n个结点的二叉树, 当且仅当其每一个结点都与深度为k的满二叉树中编号从1至n的结点一一对应时, 称之为完全二叉树.
从满二叉树和完全二叉树的定义可以看出, 满二叉树是完全二叉树的特殊形态, 即如果一棵二叉树是满二叉树, 则它必定是完全二叉树.需要注意的是,满二叉树肯定是完全二叉树,而完全二叉树不一定是满二叉树。
完全二叉树的特点:叶子结点只能出现在最下层和次下层,且最下层的叶子结点集中在树的左部。
从上述文字描述可以得出先判断是否符合满二叉树,再判断是否符合完全二叉树的条件就可以确定某个二叉树是不是完全二叉树.
先来总结一下:
1. 满二叉树的节点数要i>=1,也就如果树为空,则直接返回错 ;
2. 如果树不为空,层序遍历二叉树 ;
2.1 如果一个结点,左子树为空,并且右子树不为空,则该树一定不是完全二叉树;
2.2 如果一个结点左右子树都不为空,则遍历该节点,将其左右子树入队列;
2.3 如果一个结点,左子树不为空,右子树为空,或者左右子树都为空;并且该节点之后的队列中的结点都为叶子节点;
该树才是完全二叉树,否则就不是完全二叉树;
1. 二叉树的遍历
二叉树遍历有三种方式:先序遍历、中序遍历、后序遍历。
先序遍历:访问根节点、先序遍历左子树、先序遍历右子树。
中序遍历:中序遍历左子树、访问根节点、中序遍历右子树。
后序遍历:后续遍历左子树、后续遍历右子树、访问根节点。
前序遍历:[A][2][4][8][9][5][10][J][3][6][Q][K][7][大王][小王]
中序遍历:[8][4][9][2][10][5][J][A][Q][6][K][3][大王][7][小王]
后序遍历:[8][9][4][10][J][5][2][Q][K][6][大王][小王][7][3][A]
后面是代码实现简单看看就好
package com.cn.demo.tree;
/**
* 二叉树
*/
public class BinaryTree {
private String data; // 节点的数据域
private BinaryTree leftSubtree; // 左子树
private BinaryTree rightSubtree; // 右子树
public BinaryTree(String data) {
this.data = data;
this.leftSubtree = null;
this.rightSubtree = null;
}
public void setRightSubTree(String data) {
this.rightSubtree = new BinaryTree(data);
}
public void setLeftSubTree(String data) {
this.leftSubtree = new BinaryTree(data);
}
public void makeSubTree(String leftData, String rightData) {
this.leftSubtree = new BinaryTree(leftData);
this.rightSubtree = new BinaryTree(rightData);
}
public BinaryTree getRightSubTree() {
return rightSubtree;
}
public BinaryTree getLeftSubTree() {
return leftSubtree;
}
// 先序遍历
public void preOrderTraversal() {
System.out.print("[" + this.data + "]");
if (this.leftSubtree != null) {
this.leftSubtree.preOrderTraversal();
}
if (this.rightSubtree != null) {
this.rightSubtree.preOrderTraversal();
}
}
// 中序遍历
public void inorderTraversal() {
if (this.leftSubtree != null) {
this.leftSubtree.inorderTraversal();
}
System.out.print("[" + this.data + "]");
if (this.rightSubtree != null) {
this.rightSubtree.inorderTraversal();
}
}
// 后序遍历
public void postOrderTraversal() {
if (this.leftSubtree != null) {
this.leftSubtree.postOrderTraversal();
}
if (this.rightSubtree != null) {
this.rightSubtree.postOrderTraversal();
}
System.out.print("[" + this.data + "]");
}
public static void main(String[] args) {
BinaryTree root = new BinaryTree("A");//根
root.setLeftSubTree("2");//1层
root.setRightSubTree("3");//1层
root.getLeftSubTree().setLeftSubTree("4");//2层
root.getLeftSubTree().setRightSubTree("5");//2层
root.getRightSubTree().setLeftSubTree("6");//2层
root.getRightSubTree().setRightSubTree("7");//2层
root.getLeftSubTree().getLeftSubTree().makeSubTree("8", "9");
root.getLeftSubTree().getRightSubTree().makeSubTree("10", "J");
root.getRightSubTree().getLeftSubTree().makeSubTree("Q", "K");
root.getRightSubTree().getRightSubTree().makeSubTree("大王", "小王");
System.out.print("前序遍历:");
root.preOrderTraversal();
System.out.print("\n中序遍历:");
root.inorderTraversal();
System.out.print("\n后序遍历:");
root.postOrderTraversal();
}
}
这一节只是为后面的各种二叉树做铺垫,所以概念比较抽象没有太适合的实际应用场景.