愚昧将使你达不到任何成果,并在失望和忧郁之中自暴自弃。 --达芬奇
目录
参考书籍:《大话数据结构》--程杰
🍁一.二叉树的概念
二叉树(Binary Tree)是n(n>=0)个结点的有限集合,该集合或者为空集(称为空二叉树),或者由一个根结点和两颗互不相交的,分别称为根结点的左子树和右子树的二叉树组成。
就像树里面用孩子兄弟表示法,表示出来的树,就是链式的二叉树。
就像下面的图,就是一颗二叉树:
🍁二.二叉树的特点,结构
二叉树的特点:
1.每个结点最多有两个子树,也就是一个结点的度最多为2。
2.左子树和右子树是有顺序的,次序不能颠倒。
3.某个结点只有一颗子树,也要区分它是左子树还是右子树。
就像下面这样,两个二叉树的结构是不一样的。
二叉树的五种大分类结构:
1.空二叉树
2.只有一个根节点
3.根结点只有左子树
4.根结点只有右子树
5.根结点既有左子树也有右子树
🍁三.三种特殊的二叉树
🍁1.斜树
顾名思义,斜树它一定要斜,但是不能乱斜,它还是有点讲究的。
斜树:所有的结点都只有左子树的二叉树或者所有结点都只有右子树的二叉树,两中统称为斜树。
就像下面的二叉树就是左斜树和右斜树。
这其实就很像我们之前学过的单链表,其实线性表结构就可以理解为是树的一种极其特殊的表现形式。
🍁2.满二叉树
满二叉树一样,顾名思义,主打突出一个满字,那要如何满的二叉树,才能称作满二叉树呢?
满二叉树:在一颗二叉树中,如果所有的分支结点都存在左子树和右子树,并且所有的叶子都在同一层上,这样的二叉树称为满二叉树。
如下图所示:
是不是非常对称,中国一向以对称为美,这样的二叉树我们也叫完美二叉树。
满二叉树的特点:
1.叶子结点只能出现在最后一层。
2.非叶子结点的度一定为2。
3.同样深度的二叉树,满二叉树的结点数,叶子结点数最多。
4.假设该满二叉树的高度为k,总结点数为2^k-1(使用等比数列推出来的)。第n层结点数为2^(n-1)。
🍁3.完全二叉树
完全二叉树:完全二叉树的定义是一个深度为k的有n个节点的二叉树,对树中的节点按从上至下、从左到右的顺序进行编号,如果编号为i(1≤i≤n)的结点与满二叉树中编号为i的结点在二叉树中的位置相同,那么这颗树就叫完全二叉树。
完全二叉树和满二叉树的关系:完全不一定满,但满一定完全,故而完全二叉树不一定是满二叉树,而满二叉树一定是一个完全二叉树。
完全二叉树一定是和满二叉树类似的,最后一层的结点一定是连续的,如果完全二叉树的某个结点没有右子树,那么就一定没有左子树。
就如同下面的结构:
二叉树的特点:
1.叶子结点只能出现在最下面的两层。
2.最下层的叶子结点一定集中在左边。
3.倒数第二层的叶子结点一定集中在右边。
4.如果结点的度为1,那么该结点只有左孩子,而没有右孩子。
🍁四.二叉树的性质
二叉树的几个性质还是比较重要的,在做一些二叉树的选择,填空题时,可能就会用到这些性质。
性质1:
1. 若规定根节点的层数为1,则一棵非空二叉树的第i层上最多有2^(i-1)个结点。
这个比较好理解,我们就用满二叉树来举例,它每一层的结点都是上一层的二倍,每一层的结点都是成等比数列增长的。
性质2:
2. 若规定根节点的层数为1,则深度为h的二叉树的最大结点数是2^h-1,我们还是以满二叉树来举例。
第一层:有1个根结点
第二层:有2个结点
第三层:有4个结点
第四层:有8个结点
依次类推,满二叉树的每一层的结点,都是以等比数列增长的,把它们的结点相加起来,其实就是等比数列求和,得到满二叉树的结点总数为2^h-1。
性质3:
对于任何一颗二叉树,如果它的叶子结点数为m,度为2的结点数为n,则m=n+2。这个结论记住就是,推导起来有点麻烦。
性质4:
具有n个结点的完全二叉树的深度为[logn]+1,([x]表示不大于x的最大值整数)。这个同样记住就是,推导起来比较麻烦。
性质5:
对于具有n个结点的完全二叉树,如果按照从上至下从左至右的数组顺序对所有节点从0开始编号,则对于序号为i的结点有:
1. 若i>0,i位置节点的双亲序号:(i-1)/2;i=0,i为根节点编号,无双亲节点。
2. 若2i+1>=n否则无左孩子。
3. 若2i+2>=n否则无右孩子。
这个如何理解呢?这就要说到二叉树的存储方式:顺序存储。
🍁五.二叉树的存储方式
🍁1.顺序存储
顺序结构存储就是使用数组来存储,一般使用数组只适合表示完全二叉树,因为不是完全二叉树会有空间的浪费。而现实中使用中只有堆才会使用数组来存储,关于堆马上就会讲。二叉树顺序存储在物理上是一个数组,在逻辑上是一颗二叉树。
物理上就是实实在在在内存中如何存储的,而逻辑上的就是我们想象出来的。
知道了完全二叉树的顺序存储了之后,我们就可以来理解一些上面的性质5了。
性质5:
对于具有n个结点的完全二叉树,如果按照从上至下从左至右的数组顺序对所有节点从0开始编号,则对于序号为i的结点有:
1. 若i>0,i位置节点的双亲序号:(i-1)/2;i=0,i为根节点编号,无双亲节点。
2. 若2i+1>=n否则无左孩子。
3. 若2i+2>=n否则无右孩子。
关于第一点:
双亲结点下标为i,左孩子为2*i+1,右孩子为2*i+2。
关于性质5的2,3点。
2i+1>=n,左孩子的下标超过了数组下标的范围,那么肯定就没有左孩子了呀。
2i+2>=n,同样右孩子的下标超过了数组下标的范围,那么肯定也就没有右孩子了。
🍁2.链式存储
二叉树的链式存储结构是指,用链表来表示一棵二叉树,即用链来表示元素的逻辑关系。 通常的方法是链表中每个结点由三个域组成,数据域和左右指针域,左右指针分别用来给出该结点左孩子和右孩子所 在的链结点的存储地址 。链式结构又分为二叉链和三叉链,当前我们学习中一般都是二叉链,后面学到(C++来实现)高阶数据结构如红黑树等会用到三叉链。
后面的二叉树的链式结构就是二叉链,比如说二叉树的前中后序遍历等等,都会用到二叉链来实现。
代码的表示:
typedef int BTDataType;
// 二叉链
struct BinaryTreeNode
{
struct BinTreeNode* left; // 指向当前节点左孩子
struct BinTreeNode* right; // 指向当前节点右孩子
BTDataType data; // 当前节点值域
};
// 三叉链
struct BinaryTreeNode
{
struct BinTreeNode* parent; // 指向当前节点的双亲
struct BinTreeNode* left; // 指向当前节点左孩子
struct BinTreeNode* right; // 指向当前节点右孩子
BTDataType data; // 当前节点值域
};
总结:这里我们只是简单的认识了一下二叉树,知道了二叉树一些基础知识,后续才是重头戏,像堆排序,堆排序的应用,还要二叉树的链式结构,还有很多二叉树的OJ题,够我们啃好久了。
但是世上无难事,只怕有心人,为了写堆排序和堆的应用,我自己也学习了好久,没看懂的反复反复看,手写推导公式,总算是理解透彻了。