您的位置:首页 > 其它

二叉树及堆排序

2014-12-16 11:16 302 查看
一、二叉树的定义

在计算机科学中,二叉树是每个结点最多有两个子树的有序树。通常根的子树被称作“左子树”(left subtree)和“右子树”(right subtree)。二叉树常被用作二叉查找树和二叉堆或是二叉排序树。二叉树的每个结点至多只有二棵子树(不存在出度大于2的结点),二叉树的子树有左右之分,次序不能颠倒。

二、二叉树的性质

二叉树具有以下重要性质:

性质1 二叉树第i层上的结点数目最多为2i-1(i≥1)。

证明:用数学归纳法证明:

  归纳基础:i=1时,有2i-1=20=1。因为第1层上只有一个根结点,所以命题成立。

 归纳假设:假设对所有的j(1≤j<i)命题成立,即第j层上至多有2j-1个结点,证明j=i时命题亦成立。

 归纳步骤:根据归纳假设,第i-1层上至多有2i-2个结点。由于二叉树的每个结点至多有两个孩子,故第i层上的结点数至多是第i-1层上的最大结点数的2倍。即j=i时,该层上至多有2×2i-2=2i-1个结点,故命题成立。

性质2 深度为k的二叉树至多有2k-1个结点(k≥1)。

证明:在具有相同深度的二叉树中,仅当每一层都含有最大结点数时,其树中结点数最多。因此利用性质1可得,深度为k的二叉树的结点数至多为:

20+21+…+2k-1=2k-1

故命题正确。

性质3 在任意-棵二叉树中,若终端结点的个数为n0,度为2的结点数为n2,则no=n2+1。

证明:因为二叉树中所有结点的度数均不大于2,所以结点总数(记为n)应等于0度结点数、1度结点(记为n1)和2度结点数之和:

n=no+n1+n2 (式子1)

  另一方面,1度结点有一个孩子,2度结点有两个孩子,故二叉树中孩子结点总数是:

nl+2n2

  树中只有根结点不是任何结点的孩子,故二叉树中的结点总数又可表示为:

n=n1+2n2+1 (式子2)

  由式子1和式子2得到:

no=n2+1

满二叉树和完全二叉树是二叉树的两种特殊情形。

1、满二叉树(FullBinaryTree)

 一棵深度为k且有2k-1个结点的二又树称为满二叉树。

 满二叉树的特点:

  (1) 每一层上的结点数都达到最大值。即对给定的高度,它是具有最多结点数的二叉树。

  (2) 满二叉树中不存在度数为1的结点,每个分支结点均有两棵高度相同的子树,且树叶都在最下一层上。

  【例】图(a)是一个深度为4的满二叉树。





2、完全二叉树(Complete BinaryTree)

若一棵二叉树至多只有最下面的两层上结点的度数可以小于2,并且最下一层上的结点都集中在该层最左边的若干位置上,则此二叉树称为完全二叉树。

特点:

(1) 满二叉树是完全二叉树,完全二叉树不一定是满二叉树。

(2) 在满二叉树的最下一层上,从最右边开始连续删去若干结点后得到的二叉树仍然是一棵完全二叉树。

(3) 在完全二叉树中,若某个结点没有左孩子,则它一定没有右孩子,即该结点必是叶结点。

【例】如图(c)中,结点F没有左孩子而有右孩子L,故它不是一棵完全二叉树。

【例】图(b)是一棵完全二叉树。



性质4 具有n个结点的完全二叉树的深度为





证明:设所求完全二叉树的深度为k。由完全二叉树定义可得:

  深度为k得完全二叉树的前k-1层是深度为k-1的满二叉树,一共有2k-1-1个结点。

由于完全二叉树深度为k,故第k层上还有若干个结点,因此该完全二叉树的结点个数:

n>2k-1-1。

 另一方面,由性质2可得:

n≤2k-1,

即:2k-1-l<n≤2k-1

 由此可推出:2k-1≤n<2k,取对数后有:

k-1≤lgn<k

 又因k-1和k是相邻的两个整数,故有



,

 由此即得:





注意:




三、二叉树的存储结构

二叉树是非线性结构,即每个数据结点至多只有一个前驱,但可以有多个后继。它可采用顺序存储结构和链式存储结构。
1.顺序存储结构
二叉树的顺序存储,就是用一组连续的存储单元存放二叉树中的结点。因此,必须把二叉树的所有结点安排成为一个恰当的序列,结点在这个序列中的相互位置能反映出结点之间的逻辑关系,用编号的方法从树根起,自上层至下层,每层自左至右地给所有结点编号,缺点是有可能对存储空间造成极大的浪费,在最坏的情况下,一个深度为k且只有k个结点的右单支树需要2k-1个结点存储空间。依据二叉树的性质,完全二叉树和满二叉树采用顺序存储比较合适,树中结点的序号可以唯一地反映出结点之间的逻辑关系,这样既能够最大可能地节省存储空间,又可以利用数组元素的下标值确定结点在二叉树中的位置,以及结点之间的关系。图5-5(a)是一棵完全二叉树,图5-5(b)给出的图5-5(a)所示的完全二叉树的顺序存储结构。



(a) 一棵完全二叉树 (b) 顺序存储结构
图5-5 完全二叉树的顺序存储示意图
对于一般的二叉树,如果仍按从上至下和从左到右的顺序将树中的结点顺序存储在一维数组中,则数组元素下标之间的关系不能够反映二叉树中结点之间的逻辑关系,只有增添一些并不存在的空结点,使之成为一棵完全二叉树的形式,然后再用一维数组顺序存储。如图5-6给出了一棵一般二叉树改造后的完全二叉树形态和其顺序存储状态示意图。显然,这种存储对于需增加许多空结点才能将一棵二叉树改造成为一棵完全二叉树的存储时,会造成空间的大量浪费,不宜用顺序存储结构。最坏的情况是右单支树,如图5-7 所示,一棵深度为k的右单支树,只有k个结点,却需分配2k-1个存储单元。



(a) 一棵二叉树 (b) 改造后的完全二叉树



(c) 改造后完全二叉树顺序存储状态
图5-6 一般二叉树及其顺序存储示意图



(a) 一棵右单支二叉树 (b) 改造后的右单支树对应的完全二叉树



(c) 单支树改造后完全二叉树的顺序存储状态
图5-7 右单支二叉树及其顺序存储示意图
结构5-1二叉树的顺序存储



#define Maxsize 100     //假设一维数组最多存放100个元素
typedef char Datatype;  //假设二叉树元素的数据类型为字符
typedef struct
{ Datatype bt[Maxsize];
    int btnum;
  }Btseq;




2.链式存储结构
二叉树的链式存储结构是指,用链表来表示一棵二叉树,即用链来指示元素的逻辑关系。
通常的方法是链表中每个结点由三个域组成,数据域和左右指针域,左右指针分别用来给出该结点左孩子和右孩子所在的链结点的存储地址。其结点结构为:



其中,data域存放某结点的数据信息;lchild与rchild分别存放指向左孩子和右孩子的指针,当左孩子或右孩子不存在时,相应指针域值为空(用符号∧或NULL表示)。利用这样的结点结构表示的二叉树的链式存储结构被称为二叉链表,如图5-8所示。



(a) 一棵二叉树 (b) 二叉链表存储结构
图5-8 二叉树的二叉链表表示示意图
为了方便访问某结点的双亲,还可以给链表结点增加一个双亲字段parent,用来指向其双亲结点。每个结点由四个域组成,其结点结构为:



这种存储结构既便于查找孩子结点,又便于查找双亲结点;但是,相对于二叉链表存储结构而言,它增加了空间开销。利用这样的结点结构表示的二叉树的链式存储结构被称为三叉链表。
图5-9给出了图5-8 (a)所示的一棵二叉树的三叉链表表示。



图5-9二叉树的三叉链表表示示意图
尽管在二叉链表中无法由结点直接找到其双亲,但由于二叉链表结构灵活,操作方便,对于一般情况的二叉树,甚至比顺序存储结构还节省空间。因此,二叉链表是最常用的二叉树存储方式。
结构5-2二叉树的链式存储

#define datatype char  //定义二叉树元素的数据类型为字符
typedef struct  node   //定义结点由数据域,左右指针组成
{ Datatype data;
  struct node *lchild,*rchild;
 }Bitree;


四、二叉树的遍历

二叉树的遍历有三种方式,如下:

(1)前序遍历(DLR),首先访问根结点,然后遍历左子树,最后遍历右子树。简记根-左-右。

(2)中序遍历(LDR),首先遍历左子树,然后访问根结点,最后遍历右子树。简记左-根-右。

(3)后序遍历(LRD),首先遍历左子树,然后遍历右子树,最后访问根结点。简记左-右-根
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: