310 likes | 463 Views
第 6 章 二叉树. 线性结构:每个元素都只有一个前驱和后继结点。 现实许多事物的关系没有这么简单,如社会机构组成、城市交通通讯等,事物的联系是 非线性 的:数据元素具有两个以上的前驱或后继结点。 树型结构 是一类重要的非线性数据结构,其中以树和二叉树最为常用。 本章讨论 二叉树的存储结构 及其各种 操作 ,并研究树和森林与二叉树的 转换关系 ,最后介绍几个应用例子。下一章进展到具有一般意义的树结构。. 第 6 章 二叉树. 6.1 二叉树的定义与性质 6.2 二叉树的基本操作与存储 6.3 二叉树的遍历 6.4 线索二叉树 6.5 二叉树的应用.
E N D
第6章 二叉树 线性结构:每个元素都只有一个前驱和后继结点。 现实许多事物的关系没有这么简单,如社会机构组成、城市交通通讯等,事物的联系是非线性的:数据元素具有两个以上的前驱或后继结点。 树型结构是一类重要的非线性数据结构,其中以树和二叉树最为常用。 本章讨论二叉树的存储结构及其各种操作,并研究树和森林与二叉树的转换关系,最后介绍几个应用例子。下一章进展到具有一般意义的树结构。
第6章 二叉树 • 6.1 二叉树的定义与性质 • 6.2 二叉树的基本操作与存储 • 6.3 二叉树的遍历 • 6.4 线索二叉树 • 6.5 二叉树的应用
6.1 二叉树的定义与性质 6.1.1 基本概念 • 二叉树(Binary Tree)是有限个元素的集合: • 或者为空 • 或者是由一个根结点加上两棵互不相交的二叉树组成(分别称为左子树和右子树)
L R L R 二叉树的五种不同形态 6.1 二叉树的定义与性质 6.1.1 二叉树的基本概念 • 二叉树是有序的。 • 二叉树的子树有左右之分。 • 有5种基本形态。
1层 A 2层 B C height = 4 3层 D E F G 4层 H I J • 结点 • 结点的度 • 树的度 • 分支结点 • 叶结点 • 子女(左右) • 双亲 • 兄弟 • 祖先 • 子孙 • 结点层次 • 树的高(深)度 • 满二叉树 • 完全二叉树
M M O N K H H K L L J J I I 两种特殊的二叉树 • 满二叉树:所有的分支结点都有左右子树,所有的叶子结点都在同一层上。 A A B B C C D F E G D F E G 非满二叉树 满二叉树
M O O H K N N H L L J I I A A B B C C D F D F E G G 非满二叉树 非满二叉树
K H K H L L J I I 两种特殊的二叉树 • 完全二叉树:叶子结点只出现在最下层和次下层,并且最下层的叶子结点集中在树的左边。 • 满二叉树必定是完全二叉树,完全二叉树不一定是满二叉树。 A A B B C C D F E G D F E G 完全二叉树 非完全二叉树
二叉树的抽象数据类型 ADT BinaryTree { 数据对象D:具有相同特性的数据元素的集合。 数据关系R: 若D= Φ,则R=Φ,称BinaryTree为空二叉树; 若D!= Φ,则R={H},H是如下二元关系: (1)在D中存在唯一的根root,它在关系H 下无前驱; (2)若D-{root}!=Φ,则存在D-{root}={Dl,Dr},且Dl∩Dr=Φ; (3)若Dl=Φ,则Dl中存在唯一的元素xl,<root,xl>∈H,且存在Dl上的关系H1为H的子集;Dr同样; H={<root,xl>,<root,xr>,Hl,Hr}; (4)(Dl,{Hl})是一棵符合本定义的二叉树,称为根的左子树,(Dr,{Hr})是一棵符合本定义的二叉树,称为根的右子树。
2. 二叉树的性质 性质1 二叉树的第i层上至多有2i-1个结点(i≥1)。 利用归纳法容易证得此性质。 (1)i=1时,只有一个根结点。 显然,2i-1=20=1。 (2)假定对所有的j,1≤j<i,命题成立,即第j层上至多有2j-1个结点。那么,现在来证明j=i时命题也成立。 (3)由归纳假设:第i-1层上至多有2i-2个结点。由于二叉树的每个结点的度至多为 2,故在第i层上的最大结点数为第i-1层上的最大结点数的2倍,即2*2i-2=2i-1。
性质2 深度为k的二叉树至多有2k-1个结点(k≥1)。 由性质1,二叉树的第i层上至多有2i-1个结点(i≥1)。则深度为k的二叉树的结点总数为
性质3对任何一棵二叉树T,如果其终端结点数为n0,度为2的结点数为n2,则n0=n2+1。性质3对任何一棵二叉树T,如果其终端结点数为n0,度为2的结点数为n2,则n0=n2+1。 设n1为二叉树T中度为1的结点数。因为二叉树中所有结点的度均小于或等于2所以其结点总数为 n=n0+n1+n2 (6—1) 再看二叉树中的分支数。除了根结点外,其余结点都有一个分支进入,设B为分支总数,则n=B+1。由于这些分支是由度为1或2的结点射出的,所以又有B=n1+ 2n2。 n=n1+2n2+1 (6—2) 于是得由式(6—1)和(6—2)得 n0=n2+1
性质4具有n个结点的完全二叉树的深度为[ log2n ]+1。 证明:假设深度为k,则根据性质2和完全二叉树的定义有 2k-1-1<n≤2k-1或 2k-1≤n<2k 于是k-1≤log2n<k 因为k是整数,所以 k = [ log2n ]+1。
[i/2] i … i i+1 i+1 … 2i 2i+1 2i+2 2i+3 2i+2 2i+3 2i 2i+1 性质5如果对一棵有n个结点的完全二叉树(其深度为[log2n]+1)的结点按层序编号(从第1层到第[log2n]+1层,每层从左到右),则对任一结点i(1≤i≤n),有 (1)如果i=1,则结点i是二叉树的根,无双亲;如果i>1,则其双亲PARENT(i)是结点[ i/2 ]。 (2) 如果2i>n,则结点i无左孩子(结点i为叶子结点);否则其左孩子LCHILD(i)是结点2i。 (3)如果2i+1>n,则结点i无右孩子;否则其右孩子RCHILD(i)是结点2i+1。 (a)结点i和i+1在同一层上 (b)结点i和i+1不在同一层上 完全二义树中结点i和i+1的左、右孩子
只要先证明(2)和(3),便可以从(2)和(3)导出(1)。 • 对于i=1,由完全二叉树的定义,其左孩子是结点2。若2>n,即不存在结点2,此时结点i无左孩子。结点i的右孩子也只能是结点3,若结点3不存在,即3>n,此时结点i无右孩子。 • 对于i>1可分两种情况讨论: (1)设第j (1≤j≤[log2n] )层的第一个结点的编号为i(由二叉树的定义和性质2可知i=2j-1),则其左孩子必为第j+1层的第一个结点,其编号为2j=2(2j-1)=2i,若2i>n,则无左孩子;其右孩子必为第j+1层的第二个结点,其编号为2i+1,若2i+1>n,则无右孩子; (2)假设第j(1≤j≤[log2n])层上某个结点的编号为i(2j-1≤i<2j-1),且2i+1<n,则其左孩子为2i,右孩子为2i+1,则编号为i+1的结点是编号为i的结点的右兄弟或者堂兄弟,若它有左孩子,则编号必为2i+2=2(i+1),若它有右孩子,则其编号必为2i+3=2(i+1)+1。
第6章 二叉树 • 6.1 二叉树的定义与性质 • 6.2 二叉树的基本操作与存储 • 6.3 二叉树的遍历 • 6.4 线索二叉树 • 6.5 二叉树的应用
6.2 二叉树的操作与存储结构 6.2.1 二叉树的存储 一、顺序存储结构 用一组连续的存储单元按照从上到下、从左到右的次序存放二叉树的结点。 #define MAX_TREE_SIZE 100 //二叉树的最大结点数 typedef DataType SqBiTree[MAX_TREE_SIZE]; //0号单元存储根结点 SqBiTree bt;
H K L J J I A A B B C C D F E G D F E (a)完全二叉树 (b)一般二叉树 0 1 2 3 4 5 A B C E F J ? 二叉树的顺序存储结构
D H I J • 完全二叉树的顺序存储可利用数组下标确定结点之间的逻辑关系。 • 一般二叉树则不能。可增加空结点来实现。 A B C 缺点:浪费存储空间。 D G F E 建立二叉树
PARENT DATA LCHILD RCHILD lchild data rchild lchild data parent rchild 二、链式存储结构 • 二叉树的链表中的结点包含三个域:数据域和左、右指针域。二叉链表 • 为了便于找到结点的双亲,则增加一个指向双亲结点的指针域。三叉链表 二叉树的结点 含有两个指针域的结点 含有三个指针域的结点
A B C D 单支树的二叉链表 A B C D • 容易证得,在含有n个结点的二叉链表中有n+1个空链域。
A A B B C D C D E F E F D C B A G F E G G (1)二叉链表 (2)三叉链表 • 可以利用这些空链域存储其它有用信息,从而得到另一种链式存储结构—线索链表。
二叉树的链表存储表示: typedef struct BiTNode { DataType data; struct BiTNode *lchild, *rchild; }BiTNode, *BiTree;
6.2.2 二叉树的基本操作及实现 InitBiTree(&T); 操作结果:构造空二叉树T。 DestroyBiTree(&T); 初始条件:二叉树T存在。 操作结果:销毁二叉树T。 CreateBiTree(&T,definition) 初始条件:definition给出二叉树T的定义。 操作结果:按definition构造二叉树T。 ClearBiTree(&T); 初始条件:二叉树T存在。 操作结果:将二叉树T清为空树。 BiTreeEmpty(T); 初始条件:二叉树T存在。 操作结果:若T为空二叉树,则返回TRUE,否则FALSE。 BiTreeDepth(T); 初始条件:二叉树T存在。 操作结果:返回T的深度。 ………………………………………
常用的操作算法 • //建立空二叉树 int Initiate(BiTree *bt) { bt=new BiTNode; if(!bt) return 0; bt->lchild=NULL; bt->rchild=NULL; return 1; }
常用的操作算法 • //建立已生成左右子树的二叉树 int Create(DataType x, BiTree lbt, BiTree rbt) { BiTree p; p=new BiTNode; if(!p) return NULL; p->data=x; p->lchild=lbt; p->rchild=rbt; return p; }
A B D F G E 常用的操作算法 • //给二叉树的某结点插入一个左孩子 BiTree InsertL(BiTree bt, DataType x, BiTree parent) { BiTree p; if(parent==NULL) { cout<<“插入错误”<<endl; return NULL; } p=new BiTNode; if(!p) return NULL; p->data=x; p->lchild=NULL; p->rchild=NULL; if(parent->lchild==NULL) parent->lchild=p; else { p->lchild=parent->lchild; parent->lchild=p; } return bt; }
A B D F G E 常用的操作算法 • //删除二叉树中某结点的左子 树 BiTree DeleteL(BiTree bt, BiTree parent) { BiTree p; if(parent==NULL||parent->lchhild==NULL) { cout<<“删除错误”<<endl; return NULL; } p=parent->lchild; parent->lchild=NULL; delete p; return bt; }
第6章 二叉树 • 6.1 二叉树的定义与性质 • 6.2 二叉树的基本操作与存储 • 6.3 二叉树的遍历 • 6.4 线索二叉树 • 6.5 二叉树的应用
6.3 遍历二叉树 • 二叉树的应用:查找结点,对全部结点逐一进行某种处理。 • 遍历二叉树(Traversing Binary Tree):按某条路径访问树中每个结点,每个结点均被且仅被访问一次。 • 二叉树的每个结点都可能有两棵子树,因此要找一种规律,使二叉树上的结点线性排列,便于遍历。
根据二叉树的递归定义: 根结点、左子树和右子树。 以L、D、R分别表示遍历左子树、访问根结点和遍历右子树,则有六种遍历方案: DLR、LDR、LRD、DRL、RDL、RLD 若限定先左后右,则只有前三种情况: 先序遍历,中序遍历和后序遍历。