1、树的定义:
树是一种非线性的数据结构,它是由n个有限节点组成一个具有层次关系的集合,
*有一个特殊的节点,成为根节点,根节点没有前驱节点
*除根结点外,其余节点被分成M个互不相交的集合T1、T2、...、Tm,其中,每一个集合Ti(1<i<m)又是一棵与树类似的子树,每棵子树的根节点都只有一个前驱,可以有0个或多个后继
*树是递归定义的
2、概念
*节点的度:一个节点含有子树的个数称为该节点的度;如上图,A的度为6
*树的度:一棵树中,所有节点的度的最大值称为树的度,如上图,树的度为6
*叶子节点或终端节点:度为0的节点成为叶子节点;如上图:B、C、H、I、....都是叶子节点
*双亲节点或父节点:若一个节点含有子节点,则这个节点称为该子节点的父节点,如上图A是B的父节点
*孩子节点或子节点:一个节点含有的子树的根节点称为该节点的子节点;如上图B 是A的字节点
*根节点:一棵书中没有双亲节点的节点,如上图的A
*节点的层次:从根开始定义起,根为第一层,根的字节点为第二层,依次类推
*树的高度或深度:树中节点的最大层次;如上图,树的高度为4
*非终端节点或分支节点:度不为0的节点,如上图D、E、F、G...都是分支节点
*兄弟节点:具有相同父节点的节点互为兄弟节点;如上图的B、C互为兄弟节点
*堂兄弟节点:双亲都在同一层的节点互为堂兄弟;如上图的H、I;
*节点的祖先:从根到该节点所经过的所有节点都是该节点的祖先节点,如上图A是所有节点的祖先
*子孙:以某节点为根的子树中任意节点都是该节点的子孙;如上图所有节点都是A的子孙
森林:由m棵不相交的树组成的集合称为森林
3、树的模拟实现
*定义一个树的类:孩子兄弟表示法
class Node {
int value; // 树中存储的数据
Node firstChild; // 第一个孩子引用
Node nextBrother; // 下一个兄弟引用
}
4、二叉树
一棵二叉树是节点的有限集合,该集合:
1、或者为空
2、或者是由一个根节点加上两棵分别称为左右子树的二叉树组成
由上图可以看出:
*不存在度大于2的节点
*二叉树的子树有左右之分,次序不能颠倒,因此二叉树是有序树
5、概念
*满二叉树:一棵二叉树,如果每层的节点树都达到最大值,则这颗树就是满二叉树,也就是说,如果一个树的层数为K,且节点总数为2^K-1,则它就是满二叉树
*完全二叉树:对于深度为k的,有n个节点的二叉树,当且仅当其每一个节点都深度为k的满二叉树中编号从0~n-1的节点——对应时称之为完全二叉树,满二叉树是一个特殊的完全二叉树
6、二叉树的性质
*若规定根节点的层数为1,则一棵非空二叉树的第i层上最多有2^(i-1) (i>0)个节点
*若规定只有根节点的二叉树的深度为1,则深度为k的二叉树的最大节点数是2^k-1(k>=0)
*对任何一棵二叉树,如果其叶子节点个数为n0,度为2的非叶子节点个数为n2,则n0=n2+1
*具有n个节点的完全二叉树的深度K为log2(k+1)上取整
*对于具有n个节点的完全二叉树,如果按照从上至下从左至右的顺序对所有节点从0开始进行编号,则对于序号为i的节点有:
若i>0,双亲序号:(i-1)/2; i=0 ,i为根节点编号,无双亲节点
若2i+1<n,左孩子序号:2i+1,否则无左孩子
若2i+1<n,右孩子序号:2i+2,否则无右孩子
7、二叉树的存储
二叉树的存储结构分为:顺序存储和类似于链表的链式存储
8、二叉树的模拟实现-孩子表示法
//定义一个表示节点的一个类
public static class TreeNode{
//当前节点的值
int value;
//左节点
TreeNode left;
//右节点
TreeNode right;
public TreeNode(int value) {
this.value = value;
}
}
public void creat(){
TreeNode node1=new TreeNode(1);
TreeNode node2=new TreeNode(2);
TreeNode node3=new TreeNode(3);
TreeNode node4=new TreeNode(4);
TreeNode node5=new TreeNode(5);
TreeNode node6=new TreeNode(6);
TreeNode node7=new TreeNode(7);
node1.left=node2;
node1.right=node3;
node2.left=node4;
node2.right=node5;
node3.left=node6;
node3.right=node7;
root=node1;
}
public TreeNode root;
9、二叉树的遍历
*NLR:前序遍历(先序遍历)——访问根结点--->根的左子树--->根的右子树。
*LNR:中序遍历——根的左子树--->根节点--->根的右子树。
*LRN:后序遍历——根的左子树--->根的右子树--->根节点。
*先序遍历
方法1
/**
* 先序遍历
* @param root
*/
public void preOrder(TreeNode root){
//如果节点为空就返回
if(root==null){
return;
}
//先序遍历:中左右
//处理根节点
System.out.println(root.value);
//处理左子树
preOrder(root.left);
//处理右子树
preOrder(root.right);
}
方法二
//定义一个list保存二叉树节点的值
List<Integer> preOrderlist=new ArrayList<>();
public List<Integer> preOederTree(TreeNode root){
//前序遍历
if(root==null){
return null;
}
preOrderlist.add(root.value);
preOederTree(root.right);
preOederTree(root.left);
return preOrderlist;
}
方法三-子问题思路
public List<Integer> preOrderTree1(TreeNode root){
//定义一个list集合
List<Integer> list=new ArrayList<>();
//前序遍历子问题思路
if(root==null){
return list;
}
//先把根节点的值加入list集合里面
list.add(root.value);
//处理左子树
List<Integer> leftNode=preOrderTree1(root.left);
list.addAll(leftNode);
//处理右子树
List<Integer> rightNode=preOrderTree1(root.right);
list.addAll(rightNode);
return list;
}
*中序遍历
/**
* 中序遍历
*/
public void minOrder(TreeNode root){
//如果根节点为空返回
if(root==null){
return;
}
//处理左子树
minOrder(root.left);
//处理根节点
System.out.println(root.value);
//处理右子树
minOrder(root.right);
}
*后序遍历
//后序遍历:左-右-根
public void bihindOrder(TreeNode root){
//如果根节点为空返回
if(root==null){
return;
}
//处理左节点
bihindOrder(root.left);
//处理右节点
bihindOrder(root.right);
//打印根结点
System.out.println(root.value);
}
*节点个数
/**
* 节点个数
* @param root
* @return
*/
public int size(TreeNode root){
//1、终止条件,(一个空树,一个叶子节点)
if(root==null){
return 0;
}
//2、如果只有一个根节点返回1
//3、处理左子树
int leftTreeNode=size(root.left);
//4、处理右子树
int rightTreeNode=size(root.right);
//返回节点的和:根节点+左节点+右节点
return 1+leftTreeNode+rightTreeNode;
}
*求叶子节点个数
1、子问题思路
子问题思路就是将一个大问题,分成N个,对于二叉树来说就是分成两个,分别去求解这些子问题,最终汇总成大问题的解
//子问题思路,求叶子节点个数
public int leafNode(TreeNode root){
if(root==null){
return 0;
}
if(root.left==null&&root.right==null){
//条件满足时返回1
return 1;
}
//处理左子树
int left=leafNode(root.left);
//处理右子树
int right=leafNode(root.right);
//返回左右相加的叶子节点的总和
return left+right;
}
2、遍历思路
public int count;
public int leafNode1(TreeNode root){
if(root==null){
return 0;
}
if(root.left==null&&root.right==null){
count++;
}
leafNode1(root.left);
leafNode1(root.right);
return count;
}
*获取第k层节点的个数
//获取第k层节点的个数
public int findKNode(TreeNode root,int k){
//如果根节点或者K==0的条件下返回0
if(root==null|| k ==0){
return 0;
}
//查询终止条件
if(k==1){
return 1;
}
int leftTree=findKNode(root.left,k-1);
int rightTree=findKNode(root.right,k-1);
return leftTree+rightTree;
}
*获取二叉树的高度
//获取二叉树的高度
public int heightTree(TreeNode root){
//如果root为0,返回0
if(root==null){
return 0;
}
//利用Math.max()方法进行左右子树高度的判断
int left=heightTree(root.left);
int right=heightTree(root.right);
int high=Math.max(left,right)+1;
return high;
}
*判断是否是一棵完全二叉树
//判断是否是完全二叉树
public boolean isCompleteTree(TreeNode root){
//定义队列结构辅助保存节点
Queue<TreeNode> queue=new LinkedList<>();
//首先判空条件
if(root==null){
return true;
}
//先将根节点入队
queue.offer(root);
//循环条件:队列不为空
while(!queue.isEmpty()){
//根节点出队,保存node
TreeNode node=queue.poll();
if(node!=null) {
//节点不为空,不管左右节点是否为空,全部入队
queue.offer(root.left);
queue.offer(root.right);
}else{
//当node为空的时候,将队列元素全部出队,
while(queue.isEmpty()){
//当出队元素不为null时就不是一个完全二叉树,返回false
TreeNode checkNode=queue.poll();
if(checkNode!=null){
return false;
}
}
}
}
//最后返回true
return true;
}
*层次遍历
/**
* 层次遍历
* @param root
* @return
*/
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> list1=new ArrayList<>();
if(root==null){
return list1;
}
Queue<TreeNode> queue=new LinkedList<>();
queue.offer(root);
while(!queue.isEmpty()){
List<Integer> list=new ArrayList<>();
int size=queue.size();
while(size>0){
TreeNode node=queue.poll();
list.add(node.value);
if(root.left!=null){
queue.offer(node.left);
}
if(root.right!=null){
queue.offer(node.right);
}
size--;
}
list1.add(list);
}
return list1;
}
*测试类
public class TextBinaryTree {
public static void main(String[] args) {
Day20221022.Tree.BinaryTree binarytree=new BinaryTree();
binarytree.creat();
System.out.println(binarytree.preOederTree(binarytree.root));
System.out.println("二叉树的节点的个数");
System.out.println(binarytree.size(binarytree.root));
System.out.println("子问题遍历二叉树叶子节点的个数");
System.out.println(binarytree.leafNode(binarytree.root));
System.out.println("遍历二叉树叶子节点个数");
System.out.println(binarytree.leafNode1(binarytree.root));
System.out.println("查询第K层节点的个数");
System.out.println(binarytree.findKNode(binarytree.root,2));
System.out.println("查询树的高度");
System.out.println(binarytree.heightTree(binarytree.root));
System.out.println("是否是一棵完全二叉树");
System.out.println(binarytree.isCompleteTree(binarytree.root));
System.out.println("===============");
}
}
结果