日升时奋斗,日落时自省
目录
一、树的结构
树的数据结构与树相同,但是根部向上,树枝向下,树是一种非线性的数据结构,它是由n(n>=0)个有限结点组成一个具有层次关系的集合。
可见左边的“真”树,右边自然就是我们要学习的树据结构
这里有一个特殊的节点就是根节点了,根节点没有前驱节点
(1)A就是根节点,无前驱节点
(2)除了根节点以外的节点都有后驱,后驱个数0或者n个
(3)树是有递归定义的
树注意:
(1)子树不能相交
(2)每个子树只能有个父亲节点
(3)有n个节点的树,有n-1条边
二、二叉树
二叉树就是树的基础上加上了一定的限制条件
2.1树相关的基本概念
1、结点的度:一个结点含有子树的个数称为该结点的度; 如上图:A的度为2
2、树的度:一棵树中,所有结点度的最大值称为树的度; 如上图:树的度为2
3、叶子结点或终端结点:度为0的结点称为叶结点; 如上图:D、E、F、G节点为叶结点
4、双亲结点或父结点:若一个结点含有子结点,则这个结点称为其子结点的父结点; 如上图:A是B,也是C的父结点,B是D、E的父节点,C是F、G的父节点
5、孩子结点或子结点:一个结点含有的子树的根结点称为该结点的子结点; 如上图:B、C是A的孩子结点 依次类推是同样的 D、E是B的子节点,F、G是C的子节点
6、根结点:一棵树中,没有双亲结点的结点;如上图:A
7、结点的层次:从根开始定义起,根为第1层,根的子结点为第2层,以此类推
8、树的高度:树中结点的最大层次; 如上图:树的高度为3
9、深度:深度相较于节点,高度是最大的深度,那从B节点来看深度就是2,就相当于把B当成一个根节点B是根节点的一棵树
一下作为了解(知道就行)
(1)非终端结点或分支结点:度不为0的结点; 如上图:D、E、F、G节点为分支结点
(2)兄弟结点:具有相同父结点的结点互称为兄弟结点; 如上图:B、C是兄弟结点,D、E也是兄弟节点
(3)堂兄弟结点:双亲在同一层的结点互为堂兄弟;如上图:E、F互为堂兄弟结点
(4)结点的祖先:从根到该结点所经分支上的所有结点;如上图:A是所有结点的祖先,B、A都是D的祖先节点,这里B也是D的父亲节点,也是祖先节点
(5)子孙:以某结点为根的子树中任一结点都称为该结点的子孙。如上图:所有结点都是A的子孙
(6)森林:由m(m>=0)棵互不相交的树组成的集合称为森林
2.2树的代码形式
代码形式可以区分为双亲表示法,孩子表示法、孩子双亲表示法、孩子兄弟表示法等等,这里我们经常看见的是孩子兄弟表示法
class Node {
int value; // 树中存储的数据
Node firstChild; // 第一个孩子引用
Node nextBrother; // 下一个兄弟引用
}
按照上图的样子,代码呈现的图像技术这个样子
2.3树的应用
文件管理目录
2.4二叉树分析
现在来说二叉树相较于普通的条件,二叉树的度<=2,二叉树中每个子树的度都是<=2的;
二叉树看上去已经是比较特殊,在二叉树中有更特殊的存在
1、满二叉树:每层的节点树都是满的就像之前看到的这课树,这样的树便于我们计算节点个数
如果有一个k层的满二叉树,节点数:
-1
2、完全二叉树:是数据结构中效率很高,它是由满二叉树改变而来的所以如何改变的呢,就是它不一定会有右边节点,但是存在右边节点的话就一定存在左边节点
2.5二叉树的算术特点
1. 若规定根结点的层数为1,则一棵非空二叉树的第i层上最多有
(i>0)个结点
1、解释:满二叉树最底层可以实现最大节点树,如下图依次类推即可
2. 若规定只有根结点的二叉树的深度为1,则深度为K的二叉树的最大结点数是(k>=0)
2、解释:如果是满二叉树的话,那就是从我们刚刚看到开始算每一层的节点个数,这里会用到等比求和的公式
3. 对任何一棵二叉树, 如果其叶结点个数为 n0, 度为2的非叶结点个数为 n2,则有n0=n2+1
3、图解:
4. 具有n个结点的完全二叉树的深度K为
上取整,也可以是
下取整
4、图解:
2.6二叉树算术练习
1. 某二叉树共有 399 个结点,其中有 199 个度为 2 的结点,则该二叉树中的叶子结点数为(c)
A 不存在这样的二叉树
B 200
C 198
D 199
我们可以用公式n0=n2+1这里已经知道n2=199 n0=200
2.在具有 2n 个结点的完全二叉树中,叶子结点个数为( )(多个条件节点个数为偶数)
A n
B n+1
C n-1
D n/22n=n0+n2+1=n2+1+n2+1=2*n2+1+1
n2=n-1
3.一个具有767个节点的完全二叉树,其叶子节点个数为()
A 383
B 384
C 385
D 386767是奇数=n0+n2=2*n+1
n2=383
n0=n2+1=384
4.一棵完全二叉树的节点数为531个,那么这棵树的高度为( )
A 11
B 10
C 8
D 12向上取整
n=10
2.7二叉树的表示方法
通过前面的基础,现在以不同方式再来表示一下不同形式的代码
(1)孩子表示法
class Node {
int val; // 数据域
Node left; // 左孩子的引用,常常代表左孩子为根的整棵左子树
Node right; // 右孩子的引用,常常代表右孩子为根的整棵右子树
}
(2)孩子双亲表示法
class Node {
int val; // 数据域
Node left; // 左孩子的引用,常常代表左孩子为根的整棵左子树
Node right; // 右孩子的引用,常常代表右孩子为根的整棵右子树
Node parent; // 当前节点的根节点
}
先建立一棵树来为后续代码铺路
public class TestBinaryTree {
static class TreeNode{
public char val; //数据
public TreeNode left; //左孩子
public TreeNode right; //右孩子
public TreeNode(char val){ //构造方法赋值
this.val=val;
}
}
private TreeNode root;
public void createTree(){ //手动建立一个树
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');
root=A;
A.left=B;
A.right=C;
B.left=D;
B.right=E;
C.left=F;
C.right=G;
E.right=H;
}
}
学习了一种数据结构,我就会想如何遍历它,树的遍历方式有三种,前序遍历,中序遍历,后续遍历
2.7.1前序遍历
可以记住这么一个规则:根->左树->右树
public void preOrder(TreeNode root){
if(root==null){
return;
}
System.out.println(root.val);
preOrder(root.left);
preOrder(root.right);
}
前序遍历结果: A B D E H C F G
红色箭头表示每次到递归下去,蓝色表示返回上来,从根到左树,再到右树,如上图依次类推
2.7.2中序遍历
中序遍历规则:左子树->根->右子树
public void inOrder(TreeNode root){
if(root==null){
return;
}
inOrder(root.left);
System.out.println(root.val);
inOrder(root.right);
}
中序遍历结果: D B E H A F C G
2.7.3后序遍历
后序遍历的规则:左子树->右子树->根
public void postOrde(TreeNode root){
if(root==null){
return;
}
postOrde(root.left);
preOrder(root.right);
System.out.println(root.val);
}
后序遍历结果:D H E B F G C A