树
树形结构
概念
树是一种非线性的数据结构 ,它是由n(n>=0)个有限节点 组成的一个具有层次关系的集合。把他叫做树是因为它看起来像一颗倒挂的树,也就是说他是跟朝上,而叶朝下的。
1.有根节点,根节点没有前驱节点 ,除了根节点之外,其余节点被分成M(M>0)个互不相交的集合 T1、T2、...... 、Tm,其中每个集合又是一颗于树类似的子树 。每棵子树的根节点 有且只有一个前驱,可有多个后继
树是递归定义的

注意: 树形结构中,字树之间不能有交集,否则就不是树形结构
概念

节点的度: 一个节点含有子树的个数,A的度为6
树的度: 一棵树中,所有节点度最大值称为树的度,上图中树的度为6
叶子节点/终端节点:度为0的节点称为叶节点,B C H....是叶子节点
双亲节点/父节点: 若一个节点含有子节点,则这个节点称为其子节点的父节点,A是B的父节点
孩子节点/子节点: 一个节点含有的子树的根节点称为该节点的子节点,B是A的子节点
根节点: 一个树中没有双亲结点的节点,A
节点的层次: 从根开始定义 ,根为一层,往下依次增加
树的高度或深度:树中节点的最大层次
非终端节点:度不为0的节点
兄弟节点:BC
堂兄弟节点:双亲在同一层
节点的祖先: 从根节点到该节点所经分支上所有的节点 A是所有节点的祖先
子孙:以某一节点为根 的子树中任意节点都称为该节点的子孙。所有节点都是A的子孙
森林: 由m(m>=0)棵互不相交的树 组成的集合称为森林
树的表现形式
树有很多种表示方法,如双亲表示法,孩子表示发,孩子双亲表示法,孩子兄弟表示法 。我们这里简单了解其中最常用的孩子兄弟表示法
java
class Node {
int value; // 树中存储的数据
Node firstChild; // 第一个孩子引用
Node nextBrother; // 下一个兄弟引用
}

树的应用
文件管理系统(目录和文件)

二叉树
一颗二叉树是节点的一个有限集合,该集合:
1.或者为空
2. 或者是由一个根节点加上两颗别称为左子树和右子树的二叉树组成

从上图看出
1. 二叉树不存在度大于2 的节点
2. 二叉树的子树有左右之分,次序不能颠倒,因此二叉树是有序树
二叉树的几种组合:

特殊的二叉树
1.满二叉树: 一颗二叉树,如果每一层的节点都达到最大值 ,则这颗二叉树就是满二叉树。也就是说,如果有一颗二叉树的层数为k ,且节点总数为2^k-1,则他是满二叉树
2.完全二叉树:除了最后一层 ,其他层必须填满 ,最后层的节点要从左向右排列 ,左侧不能 有空位,右侧可以 有空位。满二叉树 是一种特殊的完全二叉树
计算机中数组的索引通常从0 开始,所以完全二叉树的也一般用0 来表示根节点

二叉树的性质
性质一:
对于具有n个节点的完全二叉树,如果按照从上至下从左至右的顺序对所有节点从0 开始编号,则对于序号为i的节点有:
1. 若i>0 双亲序号:(i-1)/2
2.若2i+1<n,左孩子序号:2i+1,否则无左孩子
3.若2i+2<n,右孩子序号:2i+2,否则无右孩子

性质二:
任意一个二叉树度为0的节点比度为2的节点多一个
性质三:
具有n个节点的完全二叉树深度k:log2(n+1)上取整,或者log2(n) +1向下取整

性质4:
对于编号为i(i>1)的节点,其父节点编号为i/2向下取整
二叉树的存储
二叉树的存储结构分为:顺序存储和类似于链表的链式存储
链式存储
二叉树的链式存储是通过一个一个的节点引用起来的 ,常见的表示方式有二叉和三叉表示方式
java
// 孩子表示法
class Node {
int val; // 数据域
Node left; // 左孩子的引用,常常代表左孩子为根的整棵左子树
Node right; // 右孩子的引用,常常代表右孩子为根的整棵右子树
}
// 孩子双亲表示法
class Node {
int val; // 数据域
Node left; // 左孩子的引用,常常代表左孩子为根的整棵左子树
Node right; // 右孩子的引用,常常代表右孩子为根的整棵右子树
Node parent; // 当前节点的根节点
}
二叉树遍历
范例:

遍历就是沿着某条搜索路线,依次对树中每个节点均作一次且仅作一次访问。 访问节点所做的操作 依赖于具体的应用问题(比如:打印节点的内容、节点内容加一)。

N代表节点,L代表根节点的左子树,R代表根节点的右子树
NLR:前序遍历,访问节点->根的左子树->根的右子树
java
public void preOrder(TreeNode root){
if(root==null) return;
System.out.print(root.val+" ");
preOrder(root.left);
preOrder(root.right);
}
LNR:中序遍历,根的左子树->根节点->根的右子树
java
public void preOrder(TreeNode root){
if(root==null) return;
preOrder(root.left);
System.out.print(root.val+" ");
preOrder(root.right);
}
LRN:后序遍历,根的左子树->根的右子树->根节点
java
public void preOrder(TreeNode root){
if(root==null) return;
preOrder(root.left);
preOrder(root.right);
System.out.print(root.val+" ");
}
**层序遍历:**由上到下,由左到右依次遍历
java
void levelOrder (TreeNode root){
if(root==null) return;
Queue<TreeNode> tmp=new LinkedList<>();
tmp.offer(root);
while(!tmp.isEmpty()){
TreeNode cur=tmp.poll();
System.out.print(cur.data+" ");
if(cur.left!=null) tmp.offer(cur.left);
if(cur.right!=null) tmp.offer(cur.right);
}
System.out.println();
}
二叉树的基本操作
二叉树的创建
思路一:通过输入字符串递归创建
java
private TreeNode creatTree(String str){
char c=str.charAt(i);
TreeNode root=null;
if(c!='#'){
root=new TreeNode(c);
i++;
root.left=creatTree(str);
root.right=creatTree(str);
}else{
i++;
}
return root;
}
思路二:一个一个手动创建
获取树中节点个数
思路一:遍历二叉树,只要根节点不为空,计数器加一
java
public static int nodesize;
public void size(TreeNode root){
if(root==null) return ;
nodesize++;
size(root.left);
size(root.right);
}
思路二:分成子问题,整棵树的节点=左子树的节点+右子树的节点+1,左子树和右子树又分别当作根节点
java
public int size(TreeNode root){
if(root==null) return 0;
return size(root.left)+size(root.right)+1;
}
获取叶子节点的个数
思路一:遍历二叉树,当左右节点均为空时,计数器加一
java
public static int leafCount;
public void getLeafNodeCount(TreeNode root){
if(root==null) return;
if(root.left==null&&root.right==null) leafCount++;
getLeafNodeCount(root.left);
getLeafNodeCount(root.right);
}
思路二:分成子问题,左节点的叶子加上右节点的叶子
java
public int getLeafNodeCount(TreeNode root){
if(root==null) return 0;
if(root.left==null&&root.right==null) return 1;
return getLeafNodeCount(root.left)+
getLeafNodeCount(root.right);
}
获取第k层节点的个数
思路一:遍历二叉树
java
public static int leafCount;
public void getKLevelNodeCount(TreeNode root,int k){
if(root==null) return ;
if(k==1) leafCount++;
getKLevelNodeCount(root.left,k-1);
getKLevelNodeCount(root.right,k-1);
}
思路二:分成子问题
java
public 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
java
public int getHeight(TreeNode root){
if(root==null) return 0;
int left=getHeight(root.left);
int right=getHeight(root.right);
if(left>right) return left+1;
return right+1;
}
时间复杂度:O(N)
空间复杂度:O(logN) 树的高度
检测某个元素是否存在
依次遍历二叉树
java
TreeNode find(TreeNode root, char val){
if(root==null) return null;
if(root.val==val) return root;
TreeNode t1=find(root.left,val);
if(t1!=null) return t1;
TreeNode t2= find(root.right,val);
if(t2!=null) return t2;
return null;
}
时间复杂度:O(N)
空间复杂度:O(logN)