目录
声明:结点和节点这两词都对,本文没有做区分,以下所说的节点和结点都是一个东西。
一.树的基本概念
1.树是什么
树是一种非线性的数据结构,它是由n(n>=0)个有限结点组成一个具有层次关系的集合。
因为其结构像一颗倒立的树,所以叫树。
树具有以下特点:
一个n个节点的树有 n-1 条边(每个节点上面都有一条边连着,只有根节点没有,所以是 n-1 );
有一个特殊的结点,称为根结点,根结点没有前驱结点;
子树之间不能有交集,每个子节点只有一个父节点;
树是递归定义的(重要)。
2.树的名词概念
结点度:一个结点含有子树的个数称为该结点的度,这个只针对某一个结点;
树度:一棵树中,所有结点度的最大值称为树的度;
叶子结点(终端结点):度为0的结点称为叶结点;
父节点(双亲结点):若一个结点含有子结点,则这个结点称为其子结点的父结点;
子节点(孩子结点):一个结点含有的子树的根结点称为该结点的子结点;
根结点:一棵树中,没有双亲结点的结点,最上面那一个;
结点的层次:从根开始定义起,根为第1层,根的子结点为第2层,以此类推;
树的高度(深度):树中结点的最大层次;
分支结点(非终端结点):度不为0的结点;
兄弟结点:有相同父节点的结点;
堂兄弟结点:父节点在同一层的结点。注意不只是父节点是兄弟结点,在同一层都可以;
结点的祖先:从根到该结点所经分支上的所有结点;
子孙:以某结点为根的子树中任一结点都称为该结点的子孙;
森林:由m(m>=0)棵互不相交的树组成的集合称为森林。
二.二叉树
1.概念
二叉树是一种特殊的树,顾名思义,二叉树的父节点最多有两个子节点。二叉树的子树是有顺序的,一个是左子树,一个右子树。
2.特殊的二叉树
2.1 完全二叉树
完全二叉树是效率很高的数据结构。对于深度为K的,有 n 个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从0至n-1的结点一一对应时称之为完全二叉树。
2.2 满二叉树
满二叉树一种特殊的完全二叉树,每层结点都达到最大值,即除了根节点和叶子节点其他的节点的度都为2。如果一棵二叉树的层数为K,那么结点总数是。
3.二叉树的性质
3.1 若规定根结点的层数为1,则一棵非空二叉树的第i层上最多有 (i>0)个结点。
每一个父节点最多有两个子节点,父节点下一层的节点数的最大值就是父节点数的2倍。那么第 i 层其实就是第一层的倍。
3.2 若规定只有根结点的二叉树的深度为1,则深度为K的二叉树的最大结点数是 (k>=0)。
深度即为最大层数,假设这颗树是满二叉树,那么此时结点数最多,根据满二叉树的性质我们可得最大结点数是。
3.3 对任何一棵二叉树, 如果其叶结点个数为 n0, 度为2的非叶结点个数为 n2,则有n0=n2+1。
设 度数为1的非叶节点个数为n3,结点总数为n
n = n0 + n1 + n2 ------------结点总数
n - 1 = 0 * n0 + 1 * n1 + 2 * n2 ---------结点的边
将两个式子联立可得:n0 = n2 + 1
3.4 具有n个结点的完全二叉树的深度k为 上取整(log指的是log2)。
3.5 对于具有n个结点的完全二叉树,如果按照从上至下从左至右的顺序对所有节点从0开始编号,则对于序号为i 的结点有:
若i>0,双亲序号:(i-1)/2;i=0,i为根结点编号,无双亲结点;
若2i+1<n,左孩子序号:2i+1,否则无左孩子;
若2i+2<n,右孩子序号:2i+2,否则无右孩子。
三.二叉树的模拟实现
1.二叉树的存储
二叉树有两种存储方式:顺序表存储和链式存储,这里用的是链式存储。
class Node {
e val; // 数据域
Node left; // 左孩子的引用,常常代表左孩子为根的整棵左子树
Node right; // 右孩子的引用,常常代表右孩子为根的整棵右子树
e是某一种数据类型,看实际要存什么。
2.二叉树的遍历
二叉树的遍历大体分为四种:前序、中序、后序和层序。学过离散数学的应该很熟悉,这里不深入说了,只举一个例子。
前序遍历:FBADCEGIH (根 -> 左子树 -> 右子树)
中序遍历:ABCDEFGHI (左子树 -> 根 -> 右子树)
后序遍历:ACEDBHIGF (左子树 -> 右子树 -> 根)
层序遍历:FBGADICEH (逐层)
2.1 前序遍历
public void preOrder(BTNode root) {
if(root==null){
return ;
}
System.out.print(root.value+" ");
preOrder(root.left);
preOrder(root.right);
}
利用的就是递归的思想。preOrder可以理解成应该打印函数,第一步打印当前节点,第二步去打印左子树的节点,第三步去打印右子树的节点。注意,递归是要有终止条件的,模拟一下,叶节点就没有左右子树了,所以到root==nul是就“往回走”了。
剩下的同理。
2.2 中序遍历
public void inOrder(BTNode root) {
if(root==null){
return ;
}
inOrder(root.left);
System.out.print(root.value+" ");
inOrder(root.right);
}
2.3 后序遍历
public void postOrder(BTNode root) {
if(root==null){
return ;
}
postOrder(root.left);
postOrder(root.right);
System.out.print(root.value+" ");
}
3.树中节点的个数
public int size(BTNode root) {
if(root==null){
return 0;
}
return size(root.left)+size(root.right)+1;
}
也是递归实现,某一颗树的结点个数就是左子树结点的个数+右子树结点的个数+结点本身。这个公式就可以递归下去。终止条件就是“到底了”,没子树了。
4.叶子节点的个数
public int n;
public int getLeafNodeCount(BTNode root) {
if(root==null){
return 0;
}
if(root.left==null && root.right==null){
n++;
}
getLeafNodeCount(root.left);
getLeafNodeCount(root.right);
return 0;
}
步骤:判断当前节点是不是子节点,如果是就数量++,如果不是,就找它的左子节点是不是叶节点,然后找它的右子节点是不是叶节点。
5.获取第K层节点的个数
public int getKLevelNodeCount(BTNode root, int k) {
if(root==null){
return 0;
}
if(k==1){
return 1;
}
return getKLevelNodeCount(root.left,k-1)+getKLevelNodeCount(root.right,k-1);
}
6.获取二叉树的高度
public int getHeight(BTNode root) {
if(root==null){
return 0;
}
return Math.max(getHeight(root.left),getHeight(root.right))+1;
}
树的高度等于最大层数,找最大层数,加上1就是高度。
7.检测值为value的元素是否存在
public BTNode find(BTNode root, int val) {
if(root==null){
return null;
}
if(root.value==val){
return root;
}else{
find(root.left,val);
find(root.right,val);
}
return null;
}
步骤:首先,判断当前的节点的val是不是要找的。如果不是,找它的左子树有没有,然后找它的右子树有没有。