二叉树是非线性结构,即每一个数据结点至多只有一个前驱,但能够有多个后继。它可采用顺序存储结构和链式存储结构。node
1.顺序存储结构数组
二叉树的顺序存储,就是用一组连续的存储单元存放二叉树中的结点。所以,必须把二叉树的全部结点安排成为一个恰当的序列,结点在这个序列中的相互位置能反映出结点之间的逻辑关系,用编号的方法从树根起,自上层至下层,每层自左至右地给全部结点编号,缺点是有可能对存储空间形成极大的浪费,在最坏的状况下,一个深度为k且只有k个结点的右单支树须要2k-1个结点存储空间。依据二叉树的性质,彻底二叉树和满二叉树采用顺序存储比较合适,树中结点的序号能够惟一地反映出结点之间的逻辑关系,这样既可以最大可能地节省存储空间,又能够利用数组元素的下标值肯定结点在二叉树中的位置,以及结点之间的关系。图5-5(a)是一棵彻底二叉树,图5-5(b)给出的图5-5(a)所示的彻底二叉树的顺序存储结构。spa
(a) 一棵彻底二叉树 (b) 顺序存储结构指针
图5-5 彻底二叉树的顺序存储示意图code
对于通常的二叉树,若是仍按从上至下和从左到右的顺序将树中的结点顺序存储在一维数组中,则数组元素下标之间的关系不可以反映二叉树中结点之间的逻辑关系,只有增添一些并不存在的空结点,使之成为一棵彻底二叉树的形式,而后再用一维数组顺序存储。如图5-6给出了一棵通常二叉树改造后的彻底二叉树形态和其顺序存储状态示意图。显然,这种存储对于需增长许多空结点才能将一棵二叉树改形成为一棵彻底二叉树的存储时,会形成空间的大量浪费,不宜用顺序存储结构。最坏的状况是右单支树,如图5-7 所示,一棵深度为k的右单支树,只有k个结点,却需分配2k-1个存储单元。blog
(a) 一棵二叉树 (b) 改造后的彻底二叉树it
(c) 改造后彻底二叉树顺序存储状态class
图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;