1 树
1.1 树的定义
树(Tree)是n(n>=0)个结点的有限集。在任何一棵树非空中:
(1)有且仅有一个特定的称为根(Root)的结点;
(2)当n>1时,其余结点可分为m(m>0)个互不相交的有限集T1,T2,…,Tm ,其中每一个集合本身又是一棵树,并且称为根的子树(SubTree)。
注意:树是一种非线性的数据结构,也是一种逻辑结果,同时也是一种分层结果。
1.2 相关基本术语
![](https://i-blog.csdnimg.cn/blog_migrate/175b053f1b24d217b07f2a785f31675f.png)
以上图为例讲解有关树的术语。
结点∶树的结点包含一个数据元素及若干指向其子树的分支。A、B、C、D、E等都是结点,但是结点不仅包含数据元素,而且包含指向子树的分支。例如,B结点不仅包含数据元素 B,而且包含2个指向E、F对应子树的指针。 度:结点拥有的子树数或者分支的个数称为结点的度 (Degree) 。例如,B结点有2棵子树,所以 B结点的度为2。 叶子结点:度为的结点称为叶子 (Leaf) 或终端结点。
分支结点:又叫作非终端结点,指度不为0的结点,如 A、B、C、D、E、H结点都是非终端结点。除了根结点之外的非终端结点,也叫作内部结点,如 B、C、D、E、H结点都是内部结点。
孩子结点:结点的子树的根,例如,B结点有2棵子树,所以 B结点的孩子为E、F。
双亲结点:结点的上一个结点,与孩子结点的定义相对应。例如, B结点的双亲为A。
兄弟结点:拥有同一个双亲的结点之间称为兄弟结点。例如, B结点的兄弟为C、D。
祖先结点:从根到某结点的路径上的所有结点,都是这个结点的祖先。例如,L的祖先有A、B、F。
子孙结点:以某结点为根的子树中的所有结点,都是该结点的子孙。如 B的子孙为E、F、K、L。
层次:从根开始,根为第一层,根的孩子为第二层,根的孩子的孩子为第三层,以此类推。该图的总层次为四层。
树的高度(或者深度)∶树中结点的最大层次。如例子中的树共有4层,所以高度为4。
森林 (Forest):m(m~O) 棵互不相交的树的集合。对树中每个结点而言,其子树的集合即为森林。
1.3 树的性值
(1)树中的结点数等于所有结点的度数之和加1。
(2)度为m的树中第i层上至多有个结点(i≥1)。
(3)高度为h的m叉树至多有个结点3。
(4)具有n个结点的m叉树的最小高度为向上取整。
2 二叉树
2.1 二叉树的定义
二叉树 (Binary Tree) 是另一种树型结构,它的特点是每个结点至多只有两棵子树(即二叉树中不存在度大于的结点),并且二叉树的子树有左右之分,其次序不能任意颠倒。
(1)每个结点最多只有两棵子树,即二叉树中结点的度只能为0、1、2。
(2)子树有左右顺序之分,不能颠倒。
![](https://i-blog.csdnimg.cn/blog_migrate/c22dbbc1fd40a0d96cdd67f2a2c628f9.png)
由此,二叉树的五种形态,如图所示。
(a)空二叉树
(b)仅有一个结点的二叉树
(c)只有左子树的二叉树
(d)只有右子树的二叉树
(e)左右子树都有的二叉树
注意:二叉树与度为2的有序树的一些区别,首先度为2的树,其至少存在3个结点,但是而二叉树可以为空,不存在结点。度为2的有序树的孩子结点的左右次序是相对于另一孩子结点而言的,没有明确的左右之分。若某个结点只有一个孩子结点,则这个孩子结点就无须区分其左右次序,而二叉树无论其孩子数是否为2,都需要确定其左右位置。
2.2 特殊的二叉树
(1)满二叉树:一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。. 也就是说,如果一个二叉树的层数为K,且结点总数是 (2^k) -1 ,则它就是满二叉树。满二叉树的结点要么是叶子结点,要么它有两个子结点。
(2)完全二叉树:一棵深度为k的有n个结点的 二叉树 ,对树中的结点按从上至下、从左到右的顺序进行编号,如果编号为i(1≤i≤n)的结点与 满二叉树 中编号为i的结点在二叉树中的位置相同,则这棵二叉树称为完全二叉树。
(3)二叉排序树:又称二叉查找树(Binary Search Tree),亦称二叉搜索树。是数据结构中的一类。在一般情况下,查询效率比链表结构要高。
一棵空树,或者是具有下列性质的二叉树:
1.若左子树不空,则左子树上所有结点的值均小于它的根结点的值;
2.若右子树不空,则右子树上所有结点的值均大于它的根结点的值;
3.左、右子树也分别为二叉排序树;
(4)平衡二叉树:树上任意一结点的左子树和右子树的深度之差不超过1。
2.3 二叉树的性质
性质1 在二叉树的第i层上至多有个结点(i>=1)
性质2 深度为k的二叉树至多有个结点,(k>=1)
性质3 对任何一棵二叉树T,如果其终端结点数为,度为2的结点数为
,则
=
+1
设n,为二叉树T中度为1的结点数。因为二叉树中所有结点的度均小于或等于2.所以其结点总数为
再看二叉树中的分支数。除了根结点外,其余结点都有一个分支进入,设B为分支总数﹐则n=B+1。由于这些分支是由度为1或2的结点射出的,所以又有于是得
由上两个公式得
性质4 具有n个结点的完全二叉树的深度为
证明:假设深度为k,则根据性质2和完全二叉树的定义有
或
于是 ,因为k是整数,所以
性质5 如果对一棵有n个结点的完全二叉树(其深度为)的结点按层序编号(从第1层到第
)层,每层从左到右),则对任一结点i(1≤i≤n),有
(1)如果i=1,则结点i是二叉树的根,无双亲;如果i>1,则其双亲PARENT(i)是结点。
(2)如果2i>n,则结点i无左孩子(结点i为叶子结点);否则其右孩子LCHILD(i)是结点2i。
(3)如果2i+1>n,则结点主无右孩子;否则其右孩子RCHILD(i)是结点2i+1。
我们只要先证明(2)和(3),便可以从(2)和(3)导出(1)。
对于i=1,由完全二叉树的定义﹐其左孩子是结点2。若2>n,即不存在结点2,此时结点主无左孩子。结点主的右孩子也只能是结点3,若结点3不存在,即3>n,此时结点i无右孩子。
对于i>1可分两种情况讨论:(1)设第j(1≤j≤)层的第一个结点的编号为i(由二叉树的定义和性质2可知i=
),则其左孩子必为第j+1层的第一个结点,其编号为
,若2i>n,则无左孩子;其右孩子必为第j+1层的第二个结点,其编号为2i+1,若2i+1>n,则无右孩子;(2)假设第
层上某个结点的编号为
,且2i+1≤n,则其左孩子为2i,右孩子为2i+1,又编号为i+1的结点是编号为i的结点的右兄弟或者堂兄弟,若它有左孩子,则编号必为2i+2=2(i+1),若它有右孩子,则其编号必为2i+3=2(i+1)+1。
2.4 二叉树的存储结构
可用顺序存储和链式存储两种结构来表示二叉树,但是要注意二叉树本来就是一种非线性的存储结构。
![](https://i-blog.csdnimg.cn/blog_migrate/7e6c6d405ae4955a7c40418901d09f5f.png)
2.4.1 二叉树的顺序存储
#define MAX TREE_SIZE 100
typedef int SqBiTree[MAX TREE_SIZE];
SqBitree bt;
顺序存储是采用一段连续的存储单元依次自上而下、自左往右存储完全二叉树的结点元素,即将完全二叉树上编号为i的结点元素存储在一维数组下标为i-1的分量中。
该存储方式适合运用于完全二叉树,如果采用其他一般的二叉树会造成存储空间的浪费。因为完全二叉树是按照编号顺序依次存储到一个数组中,在中间不存在没有存储的空间位置。
![](https://i-blog.csdnimg.cn/blog_migrate/404b33acf13706d3cf334a22adef4864.png)
可以看到,在上述一般的二叉树中,存储在许多空位没有存储数据造成存储空间的浪费。
2.4.2 二叉树的链式存储
二叉树的链式结构与之前学习的栈和队列的链式结构有所不同。根据二叉树的定义可知,二叉树右两个指针结点和一个数据元素。两个指针结点分别指向该结点的左、右两个子树,所以表示二叉树的链表至少包含三个域。
因此设计了含有一个数据域和两个指针域的链式结点结构,具体如下∶
![](https://i-blog.csdnimg.cn/blog_migrate/ff94eb1e9f299796658372247f03d907.png)
data表示数据域,用于存储对应的数据元素;Ichild 和 rchild分别表示左指针域和右指针域,分别用于存储左孩子结点和右孩子结点的位置。这种存储结构又称为二叉链表存储结构。
typedef struct BTNode{
int data;
struct BTNode *lchild; //左孩子
struct BYNode *rchild; //右孩子
}BTNode;