1 树形结构
概念:树是一种非线性的数据结构,它是由n个有限节点组成一个具有层次关系的集合。
- 特点:
- 有一个特殊的结点,称为根结点,根结点没有前驱结点;
- 除根结点外,其余结点被分成 M ( M >0)个互不相交的集合T1、T2........、 Tm ,其中每一个集合又是一棵与树类似的子树。每棵子树的根结点有且只有一个前驱,可以有0个或多个后继;
- 树是递归定义的;
子树是不相交的;
除了根结点外,每个结点有且仅有一个父结点;
一棵 N 个结点的树有 N -1条边。
2 二叉树
2.1概念
一棵二叉树是结点的一个有限集合,该集合:
(1)或者为空
(2)或者是由一个根节点加上两棵别称为左子树和右子树的二叉树组成。
注意:
(1)二叉树不存在度大于2的结点
(2)二叉树的子树有左右之分,次序不能颠倒,因此二叉树是有序树
2.2二叉树的性质
- 若规定根结点的层数为1,则一棵非空二叉树的第 i 层上最多有2-1( i >0)个结点
- 若规定只有根结点的二叉树的深度为1,则深度为 K 的二叉树的最大结点数是2k-1( k >=0)
- 对任何一棵二叉树,如果其叶结点个数为n0,度为2的非叶结点个数为n2,则有n0=n2+1。即叶子节点比度为2的节点多一个。
- 具有 n 个结点的完全二叉树的深度 k 为log2( n +1)上取整
- 对于具有 n 个结点的完全二叉树,如果按照从上至下从左至右的顺序对所有节点从0开始编号,的结点有:
- 若 i >0,双亲序号:( i -1)/2; i =0, i 为根结点编号,无双亲结点。
- 若2i+1< n ,左孩子序号:2i+1,否则无左孩子
- 若2i+2< n ,右孩子序号:2i+2,否则无右孩子
二叉树的节点=n0+n1+n2; n0=n2+1
3 二叉树的遍历
分为:前序遍历、中序遍历、后序遍历、层序遍历
中心思想:本质就是在不同的时机,访问数据。
- 前序遍历:先遍历根节点,再遍历左子树,再遍历右子树。
- 中序遍历:先遍历左子树,再遍历根节点,再遍历右子树。
- 后序遍历:先遍历左子树,再遍历右子树,再遍历根节点。
- 层序遍历:从二叉树的根节点出发,首先访问第一层的树根节点,然后从左到右访问第二层的节点,接着是第三层的节点,以次类推,自上而下,自作而右逐层访问树的节点。
例题:写出下图的前序遍历、中序遍历、后序遍历
前序遍历: A B D E H C F G
中序遍历: D B E H A F C G
后序遍历: D H E B F G C A
相关代码如下,注意注释!
import sun.reflect.generics.tree.Tree;
import java.util.ArrayList;
import java.util.List;
public class TestBinaryTree {
class TreeNode{
public char val;
public TreeNode left;
public TreeNode right;
//构造方法,构造一个节点
public TreeNode(char val) {
this.val = val;
}
}
//运用穷举的方法来写一个二叉树
public TreeNode creteTree() {
TreeNode A = new TreeNode('A');
TreeNode B = new TreeNode('B');
TreeNode C = new TreeNode('C');
TreeNode D = new TreeNode('D');
TreeNode E = new TreeNode('E');
TreeNode F = new TreeNode('F');
TreeNode G = new TreeNode('G');
TreeNode H = new TreeNode('H');
A.left=B;
A.right=C;
B.left=D;
B.right=E;
E.right=H;
C.left=F;
C.right=G;
return A;//根节点
}
//使用递归来实现
//前序遍历
public void preOrder(TreeNode root){
if(root==null){
return;
}
System.out.print(root.val+" ");
preOrder(root.left);
preOrder(root.right);
}
//中序遍历
public void inOrder(TreeNode root){
if(root==null){
return;
}
inOrder(root.left);
System.out.print(root.val+" ");
inOrder(root.right);
}
//后序遍历
public void postOrder(TreeNode root){
if(root==null){
return;
}
postOrder(root.left);
postOrder(root.right);
System.out.print(root.val+" ");
}
public static int count=0;
//获取数中节点的个数 遍历思路
public void size1(TreeNode root){
if(root==null){
return ;
}
count++;
//遍历这个二叉树
size1(root.left);
size1(root.right);
}
//子问题的思路
//整个树的节点=左树节点+右数节点+1
public int size2(TreeNode root){
if(root==null){
return 0;
}
//root不为空
int tmp=size2(root.left)+size2(root.right)+1;
return tmp;
}
public static int leafCount=0;
//获取叶子节点的个数 遍历思路
void getLeafNodeCount1(TreeNode root){
if(root==null){
return;
}
if(root.left==null && root.right==null){
leafCount++;
}
getLeafNodeCount1(root.left);
getLeafNodeCount1(root.right);
}
//子问题思路
int getLeafNodeCount2(TreeNode root){
if(root==null){
return 0;
}
if(root.left==null && root.right==null){
return 1;
}
int tmp=getLeafNodeCount2(root.left)+getLeafNodeCount2(root.right);
return tmp;
}
//获取第K层节点的个数
int getKLevelNodeCount(TreeNode root,int k){
if(root==null){
return 0;
}
if(k==1){
return 1;
}
return getKLevelNodeCount(root.left,k-1)+getKLevelNodeCount(root.right,k-1);
}
//获取二叉树的高度(二叉树的最大深度)
//整个树的高度=左树和右树高度的最大值+1
int getHeight(TreeNode root){
if(root==null){
return 0;
}
int leftH=getHeight(root.left);
int leftR=getHeight(root.right);
return leftH>leftR ? leftH+1 : leftR+1;
}
//检测值为value的元素是否存在
TreeNode find(TreeNode root,int val){
if(root==null){
return null;
}
if(root.val==val){
return root;
}
TreeNode ret=find(root.left,val);
if(ret !=null){
return ret;
}
ret=find(root.right,val);
if(ret !=null){
return ret;
}
return null;
}
//判断一棵树是不是完全二叉树
boolean isCompleteTree(TreeNode root){
Queue<TreeNode> queue=new LinkedList<>();
if(root!=null){
queue.offer(root);//root不为空把root放队列(queue)中
}
while(!queue.isEmpty()){
//队列不为空,弹出一个元素给cur
TreeNode cur=queue.poll();
if(cur!=null){//cur不为空把cur的左右带入队列
queue.offer(cur.left);
queue.offer(cur.right);
}else{
break;
}
}
while (!queue.isEmpty()){
TreeNode cur=queue.peek();
if(cur!=null){
return false;
}else {
queue.poll();//弹出
}
}
return true;
}
}