二叉树(Binary Tree)是N(N>=0)个结点的有限集合,该集合或者空集(空二叉树),或者由一个节点和两颗互不相交的,分别称为根结点的左子树和右子树组成。
每个结点最多有两棵子树,所以二叉树种不存在度大于2的结点。(注意:不是都需要两棵子树,而是最多可以是两棵,没有子树或者有一棵子树叶都是可以的)
左子树和右子树是有顺序的,次序不能颠倒。
即使树中某结点只有一棵子树,也要区分它是左子 树还是右子树,下面是完全不同的二叉树:
二叉树的五种基本形态
空二叉树
只有一个根节点
根节点只有左子树
根节点只有右子树
根节点既有左子树又有右子树
二叉树区分左右,因此会有五种不同的形态
满二叉树 - 特殊的二叉树
在一棵二叉树种,如果所有分支节点都存在左子树和右子树,并且所有叶子都在同一层上,这样的二叉树称为满二叉树。
满二叉树有以下特点:
-叶子只能出现在最下一层。
-非叶子节点的度肯定是2。
-在同样深度的二叉树种,满二叉树的结点个数一定最多,同时叶子也是最多。
满二叉树和完全二叉树历年都是一个重大考点,因为考生很容易混淆两者,但如果只是为了深入学习编程,那么只需要理解即可。记得我们曾说过,理解越多,需要记住的就越少。
完全二叉树
对一棵具有N个结点的二叉树按层序编号,如果编号为(1<=i<n)的结点与同样深度的满二叉树种编号为i的结点位置完全相同,则这棵二叉树就称为完全二叉树。
完全二叉树的特点有:
-叶子结点只能出现在最下两层
-最下层的叶子结点一定集中在左部连续位置。
-倒数第二层,若有叶子结点,一定都在右部连续位置。
-如果结点度为1,则该结点只有左孩子。
-同样结点树的二叉树,完全二叉树的深度最小。
注意:满二叉树一定是完全二叉树,但完全二叉树不一定是满二叉树。
二叉树的性质
性质一
在二叉树的第i层上至少有2^(i-1)个结点(i>=1)
-这个性质其实很好记忆,考试的时候懂得画出二叉树的图变可以推出。
性质二
深度为k的二叉树至多有2^k-1个结点(k>=1)
-这里一定要看清楚,是2^k再-1,看图理解老办法。
性质三:
对任何一棵二叉树Y,如果其终端结点树为n0,度为2的结点数为n2,则n0=n2+1.
-这个就比较困难了,需要推导获得。
-首选我们再假设度为1的结点数为n1,则二叉树T的结点总数n=n0+n1+n2.
-其次我们发现连接数总是等于总结点数n-1,并且等于n1 +2*n2.
-所以n-1=n1+2*n2.
-所以n0+n1+n2-1=n1+n2+n2;
-最后n0=n2+1
性质四:
具有n个结点的完全二叉树的深度为log2n 取下限+ 1
由满二叉树的定义结合性质二我们知道,深度为k的满二叉树的结点树n一定是2^k-1
那么对于满二叉树我们可以通过n=2^k-1到推得到满二叉树的深度为k=log2(n+1)
由于完全二叉树前边我们也已经提到,它的叶子结点只会出现在最下面的两层,我们可以同样如下推导
那么对于倒数第二层的满二叉树我们同样很容易回推出它的节点数为n=2^(k-1)-1
所以完全二叉树的结点树的取值范围是:2^(k-1)-1<N<2^K-1
由于n是整数,n<=2^k-1可以看成n<2^K
同理2^(k-1)-12 <n可以看成2^(k-1)<=n
所以2^(k-1)<=n<2^k
不等式两边同时取对数,得到k-1<=long2n<k
由于k是深度,必须取整,所以k=long2n取下限+1
性质五:
如果对一棵有n个结点的完全二叉树(其深度为long2n取下限+1)的结点按层序编号,对任一结点i(1<=i<=n)有一下性质:
如果i=1,则结点是二叉树的根,无双亲,如果i>1,则其双亲是结点i/2取下限
如果2i>n,则结点i无做左孩子(结点i为叶子结点),否则其左孩子是结点2i
如果2i+1>n,则结点i无右孩子,否则其右孩子是结点2i+1
二叉树的存储结构
前面的树中发现河南单单只用顺序存储结构或者链式存储结构来存放,但是二叉树是一种特殊的树,由于它的特殊性,使得用顺序存储结构或链式存储结构都能够简单实现。二叉树的顺序存储结构就是用一维数组存储二叉树种的各个结点,并且结点的存储位置能体现结点之间的逻辑关系。
少了某个元素用 ^来代替。
对于一般的二叉树,尽管层序编号不能反映逻辑关系,但是可以按照完全二叉树编号方式修改一下,把不存在的结点用^代替即可。
但是如果是斜树的话,如果右斜树三个结点就会占用8个位置来存储,极大浪费了控件。
那么既然顺序存储方式的适用性不强,那么我们就要考虑链式存储结构,二叉树的存储按照国际惯例来说一般也是采用链式存储结构。
二叉树每个结点最多有两个孩子,所以为它涉及一个数据域和两个指针域是比较自然的想法,就做二叉链表。
下图是二叉链表:
二叉树的遍历
二叉树的遍历(traversing binary tree)是指从根结点出发,按照某种次序依次访问二叉树中所有结点,使得每个结点被访问一次且仅被访问一次。
二叉树的遍历次序不同于线性结构,线性结构最多也就是分为顺序,循环,双向等简单的遍历方式。树的结点之间不存在唯一的前驱和后继这样的关系,在访问一个结点后,下一个被访问的结点面临着不同的选择。
遍历方式可以很多,如果我们限制了从左到右的习惯方式,那么主要分为四种:
-前序遍历
-中序遍历
-后序遍历
-层序遍历
前序遍历
-若二叉树为空,则空操作返回,否则先访问根节点,然后前序遍历左子树,再前序遍历右子树。
中序遍历
若树为空,则空操作返回,否则从根结点开始(注意并不是先访问根结点),中序遍历根结点的左子树,然后是访问根结点,最后中序遍历右子树。
后续遍历
若树为空,则空操作符返回,否则从左到右先叶子后结点的方式遍历访问左右子树,最后访问根结点。
层序遍历
若树为空,则返回空操作符,否则从树的第一层,也就是根结点开始访问,从上而下逐层遍历,在同一层中,按从左到右的顺序对结点逐个访问。