1 / 129

第6章 树和二叉树

第6章 树和二叉树. 6.1 树的定义和基本术语 6.2 二叉树 6.3 二叉树的遍历 习题1 6.4 线索二叉树 6.5 树和森林 习题2 6.6 哈夫曼树及应用. 6.1 树的定义和基本术语. J. I. A. C. B. D. H. G. F. E. 一、树的概念 非线性数据结构。 树的递归定义: 树( tree) 是 n(n>=0) 个结点的有限集,当 n>0 时, (1)有且仅有一个特定的称为 根( root ) 的结点;

aidan-sweet
Download Presentation

第6章 树和二叉树

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 第6章 树和二叉树 6.1 树的定义和基本术语 6.2 二叉树 6.3 二叉树的遍历习题1 6.4 线索二叉树 6.5 树和森林习题2 6.6 哈夫曼树及应用

  2. 6.1 树的定义和基本术语 J I A C B D H G F E 一、树的概念 • 非线性数据结构。 • 树的递归定义: • 树(tree)是n(n>=0)个结点的有限集,当n>0时, • (1)有且仅有一个特定的称为根(root)的结点; • (2)当n>1时,其余结点可分为m(m>0)个互不相交的有限集T1,T2,...,Tm,其中每个集合本身又是一棵树。称为子树(subtree)。

  3. J I A C B D H G F E • 例:下面的图是一棵树 T={A, B, C, D, E, F, G, H, I, J} • A是根,其余结点可以划分为3个互不相交的集合: • T1={B, E, F} , T2={C, G} , T3={D, H, I, J} • 这些集合中的每一集合都本身又是一棵树,它们是A的子树。 • 例如,对于 T1,B是根,其余结点可以划分为2个互不相交的集合: • T11={E},T12={F},T11,T12 是B的子树。

  4. J I A C B D H G F E • 树的逻辑结构特征: • 1)树中只有根结点没有前趋;其余结点都有且仅一个前趋; • 3)每个结点,可以有零个或多个后继; • 4)除根外的其他结点,都存在唯一条从根到该结点的路径; • 5)树是一种分支结构。

  5. 线性结构和树型结构比较

  6. 二、树的应用 • 1)树可表示具有分支结构关系的对象 • 例1.家族族谱 荣国公 贾 赦 贾政 贾珠 贾元春 贾宝玉 贾探春 贾环 贾琏 贾迎春 贾兰 巧姐

  7. 例2.企事业单位行政机构的组织关系

  8. 2)树是常用的数据组织形式 • 例3.计算机的文件系统 • 不论是DOS文件系统还是window文件系统,所有的文件是用树的形式来组织的。 C: 文件夹1 文件夹n 文件1 文件2 文件夹11 文件夹12 文件11 文件12

  9. 3)一些应用问题的求解过程可用树结构的来描述,以帮助程序员写出求解问题的程序或算法。3)一些应用问题的求解过程可用树结构的来描述,以帮助程序员写出求解问题的程序或算法。 • 例4. 求集合的幂集——求集合A={ 1,2,3} 的幂集 • 集合中每个元素对于子集来说,要么属于该子集,要么不属于该子集。 考虑元素 1 { } 考虑元素 2 {1} { } 考虑元素 3 {1,2} {1} {2} { } {1,2,3} {1,2} {1,3} {1} {2,3} {2} {3} { } 显然集合A中所有即为该树的所有叶子,求集合A所有子集即为求该树的所有叶子。

  10. 三、树的表示 • 1)图示表示 • 2)二元组表示 • 3)嵌套集合表示(图a) • 4)广义表表示(图b) • 5)凹入表示法(类似书的目录,图c)

  11. J I A C B D H G F E L K M • 广义表表示法 ( A ( B ( E ( K, L ), F ), C ( G ), D ( H ( M ), I, J ) ) 根作为由子树森林组成的表的名字写在表的左边

  12. 6.1 树的有关概念 J I A C B D H G F E 四、树的 基本术语 • 树的结点:包含一个数据元素及若干指向子树的分支; • 孩子(Child)结点:结点的子树的根; • 双亲 (Parent)结点:B结点是A结点的孩子,则A结点是B结点的双亲 • 兄弟(Sibling)结点:同一双亲的孩子结点; • 堂兄结点:同一层上结点;

  13. J I A C B D H G F E • 结点的层次(Level):根结点的层定义为1;根的孩子为第二层结点,依此类推; • 树的深度(高度,Depth):树中最大的结点层次; • 结点的度(Degree):结点子树的个数; • 树的度: 树中最大的结点度; • 叶子结点(Leaf):也叫终端结点,是度为0的结点; • 分支结点:度不为0的结点;

  14. J I A C B D H G F E • 有序树:子树从左至右有序的树; • 无序树:不考虑子树的顺序; • 森林:m (m≥0)棵互不相交的树集合。 树:Tree=(root, F), 其中 • 根:root • 森林:F={T1, T2, ……,Tm}, • 子树:Ti={ri, Fi} • 当m>0时,树根与子树森林的关系: RF={<root, ri>| i=1,2,…m, m>0}

  15. 五、树的基本操作 • 树的应用很广,应用不同基本操作也不同。下面列举了树的一些基本操作: • 1)初始化:InitTree(&T); • 2)销毁:DestroyTree(&T); • 3)构造:CreateTree(&T, definition); • 4)清空:ClearTree(&T); • 5)判空:TreeEmpty(T); • 6)求深度:TreeDepth(T);

  16. 7) 求根结点:Root(T); • 8)求当前结点的值:Value(T, cur_e); • 9) 给当前结点赋值:Assign(T, cur_e, value); • 10)求当前结点的双亲:Parent(T, cur_e); • 11)求当前结点的左孩子:LeftChild(T, cur_e); • 12)求当前结点的右兄弟:RightSibling(T, cur_e); • 13)插入子树:InsertChild(&T, &p, i, c); • 14)删除子树:DeleteChild(&T,&p, i); • 15)遍历:TraverseTree(T, Visit( ));

  17. 树是一种分支结构的对象,在树的概念中,对每一个结点孩子的个数没有限制,因此树的形态多种多样。树是一种分支结构的对象,在树的概念中,对每一个结点孩子的个数没有限制,因此树的形态多种多样。 • 问题1:树是非线性结构,该怎样存储? • 顺序结构,链式结构 • 问题2:树的顺序存储方案如何设计? • 问题3:树的链式存储方案如何设计? 解决思路:先研究最简单、最有规律的树,然后设法把一般的树转化为简单树。

  18. 6.2 二 叉 树 • 本章我们主要讨论一种最简单的树——二叉树。 • 6.2.1 二叉树的定义 • 6.2.2 二叉树的性质 • 6.2.3 二叉树的存储结构

  19. 6.2.1 二叉树的定义 E D C A B G F 一、二叉树的定义 • 二叉树:度不超过2的有序树。 • 说明 • 1)度不超过2 • 二叉树中每个结点最多有两颗子树 • 2)有序树 • 左、右子树次序不能颠例; • 3)二叉树的递归定义: • 二叉树或为空树,或由根结点及两棵不相交的左子树、右子树构成,且左、右子树本身也是二叉树。

  20. E D E D C C B A A B G G F F (a) (b) (a)、(b)是不同的二叉树, (a)的左子树有四个结点, (b)的左子树有两个结点,

  21. 二、二叉树的基本形态 φ (b)仅有根结点的二叉树; (a) 空二叉树 (e)左子树为空的二叉树 (d)左、右子树均为非空的二叉树 (c)右子树为空的二叉树

  22. 三、应用举例 c e a d b f + / - - * • 例1.树能用二叉树表示 • 例2. 用二叉树表示表达式(P129) • 若表达式为数或简单变量,则二叉树仅有一个根结点; • 若表达式=(左操作数)(运算符)(右操作数),则 • 运算符为根结点 • 左操作数为左子树 • 右操作数为右子树 a+b*(c-d)-e/f

  23. 甲 乙 开始 甲 乙 甲 乙 甲 乙 甲 乙 甲 乙 甲 乙 甲 乙 甲 乙 甲 乙甲 乙 甲 乙甲 乙 • 例3.双人比赛的所有可能的结局 开局连赢两局 或五局三胜

  24. 6.2.2 二叉树的性质 E D C A B G F • 性质1 • 在二叉树的第i 层上最多有2i-1个结点(i≥1)。 • 性质2 • 深度为k的二叉树最多有 2k-1 个结点(k≥1)。 • 性质3 • 设: • 二叉树叶子结点数为n0, • 度为2的结点数n2, • 则n0 = n2 +1。

  25. 两种特殊的二叉树 • 满二叉树 • 完全二叉树

  26. 1 2 3 4 5 6 7 E B A D A C C B F G • 满二叉树 • 满二叉树:深度为k,且含有2k-1个结点二叉树。 • 对满二叉树的结点编号: • 从上到下,每一层从左到右 K=2的满二叉树 K=3的满二叉树

  27. 1 F E C A E D C B D A B F G 2 3 4 5 6 • 完全二叉树 • 完全二叉树:树中所含的n个结点和满二叉树中编号从1至n的结点一一对应的二叉树。 1 2 3 4 5 6 7 满二叉树 完全二叉树

  28. B A E C A D C B D A F C E E B D G G • 即:一棵二叉树只有最下一层结点数可能未达到最大,且最下层结点都集中在该层的最左端。 (a) (b) (c) • 、(b)完全二叉树,(c) 不是完全二叉树

  29. 两个关于完全二叉树的性质 1 F A E D C B 2 3 4 5 6 • 性质4 • 具有n个结点的完全二叉树的深度为k=[log2n]+1 • 性质5: • 在完全二叉树中编号为i的结点, 1)若有左孩子,则左孩子结点编号为2i; 2)若有右孩子,则右孩子结点编号为2i+1; 3)若有双亲,则双亲结点编号为[i/2]。 注:其中[ ]表示取下整。

  30. 6.2.3二叉树的存储结构 一、二叉树的顺序存储结构 #define MAX_TREE_SIZE 100 //二叉树的最大结点数 typedef TElemType SqBiTree[MAX_TREE_SIZE]; //0号单元存储根结点 SqBiTree bt;

  31. 1 F A E D B C 2 3 4 5 6 • 完全二叉树的顺序结构 • 按编号顺序依次存储完全二叉树的元素。 0 1 2 3 4 5 6 …… A B C D E F

  32. A A E E D B D C B C G G F F 0 1 2 3 4 5 6 7 8 9 …… A B C D E F G • 一般二叉树的顺序结构 • 补齐二叉树所缺少的那些结点,对二叉树结点编号。 • 将二叉树原有结点按编号存储到 “相应”位置上 1 2 3 4 5 6 7 8 9 10

  33. [1] [2] [3] [4] [5] [6] [7] [8] [9] . [16] • 最坏情况:单支树 • K个元素的二叉树最多需要2k-1个空间 A ^ B ^ ^ ^ C ^ … D E A B C D 缺点:①浪费空间; ②插入、删除不便

  34. E F D B A C A B∧ C∧ ∧E∧ ∧D ∧F∧ 二、二叉树的链式存储结构 • 1. 二叉链表 • 每个结点至少包含三个域:数据域、左指针域、右指针域 T

  35. lchild data rchild 二叉链表的类型定义 typedef struct BiTNode { TElemType data; struct BiTNode *lchild,*rchild; }BiTNode,*BiTree;

  36. lchild data parent rchild • 2.三叉链表 • 每个结点至少包含四个域:数据域、双亲指针域、左指针域、右指针域 三叉链表的类型定义 typedef struct TriTNode { TElemType data; struct TriTNode *lchild,*rchild,*parent; }TriTNode,*TriTree;

  37. 6.3 二叉树的遍历 • 遍历 • 按某种搜索路径访问二叉树的每个结点,而且每个结点仅被访问一次。 • 访问 • 含义很广,可以是对结点作各种处理,如:修改结点数据、输出结点数据。 • 遍历是各种数据结构最基本的操作。 • 对于线性结构遍历是很容易的事。 • 二叉树是非线性结构,每个结点可能有两个后继,如何访问二叉树的每个结点?

  38. D E C G B A F 一、二叉树的遍历方法 • 二叉树由根、左子树、右子树三部分组成 • 二叉树的遍历可以分解为: • 访问根 • 遍历左子树 • 遍历右子树

  39. D E C G B A F • 令: L:遍历左子树 D:访问根结点 R:遍历右子树 • 有六种遍历方法: DLR,LDR,LRD, DRL,RDL,RLD • 若约定先左后右,有三种遍历方法: DLR、LDR、LRD,分别称为 先(根)序、中(根)序、后(根)序遍历

  40. D E C G B A F • 1.先序遍历(DLR) 若二叉树非空 (1)访问根结点; (2)先序遍历左子树; (3)先序遍历右子树。 例:先序遍历右图所示的二叉树 (1)访问根结点A (2)先序遍历左子树:即按DLR的顺序遍历左子树 (3)先序遍历右子树:即按DLR的顺序遍历右子树 先序遍历序列:A,B,D,E,G,C,F

  41. D E C G B A F • 2.中序遍历(LDR) 若二叉树非空 (1)中序遍历左子树 (2)访问根结点 (3)中序遍历右子树 例:中序遍历右图所示的二叉树 (1)中序遍历左子树:即按LDR的顺序遍历左子树 (2)访问根结点A (3)中序遍历右子树:即按LDR的顺序遍历右子树 中序遍历序列: D,B,G,E,A,C,F

  42. D E C G B A F • 3.后序遍历(LRD) 若二叉树非空 (1)后序遍历左子树 (2)后序遍历右子树 (3)访问根结点 例:后序遍历右图所示的二叉树 (1)后序遍历左子树:即按LRD的顺序遍历左子树 (2)后序遍历右子树:即按LRD的顺序遍历右子树 (3)访问根结点A 后序遍历序列: D,G,E,B,F,C,A

  43. c a e d f b + - * / - • 例:下图所示的二叉树表示表达式 a+b*(c-d)-e/f 先序、中序、后序遍历此二叉树

  44. c a e d f b + - * / - • 对表达式树进行中序,前序和后序遍历,分别得到表达式的中缀、前缀和后缀式。 • 中缀式:a + b * c – d –e / f • 前缀式:- + a * b – c d / e f • 后缀式:a b c d - * + e f /-

  45. c a e d f b + - * / - • 前缀式和后缀式都不必采用括号或优先级。 • 前缀式(波兰式): - + a * b – c d / e f • 从右到左扫描表达式, • 遇到操作数进栈, • 遇到运算符,则操作数出栈运算,中间结果进栈。 • 后缀式(逆波兰式):a b c d - * + e f /- • 从左到右扫描表达式, • 遇到操作数进栈, • 遇到运算符,则操作数出栈运算,中间结果进栈。

  46. 二. 遍历的递归算法 上面介绍了三种遍历方法,显然是用递归的方式给出的,以先序为例: • 先序遍历(DLR)的定义: 若二叉树非空 (1)访问根结点; (2)先序遍历左子树; (3)先序遍历右子树; 先序遍历的递归定义

  47. 上面先序遍历的定义等价于: • 若二叉树为空,结束 ——基本项(也叫终止项) • 若二叉树非空 ——递归项 • (1)访问根结点; • (2)先序遍历左子树 • (3)先序遍历右子树;

  48. 下面给出先序、中序、后序遍历递归算法 • 为了增加算法的可读性,这里对书上算法作了简化。 • 没有考虑访问结点出错的情况 • 我们假设调用函数visit( )访问结点总是成功的。

  49. T A B∧ C∧ ∧E∧ ∧D ∧F∧ 1.先序遍历递归算法  void PreOrderTraverse(BiTree T, Status (*Visit)(TElemType e)) { //本算法先序遍历以T为根结点指针的二叉树 //对每个数据元素调用函数Visit( ) if (T) { //若二叉树为空,结束返回 // 若二叉树不为空,访问根结点,遍历左子树,遍历右子树 Visit(T->data); PreOrderTraverse(T->lchild, Visit); PreOrderTraverse(T->rchild, Visit); } }//PreOrderTraverse

  50. 最简单的Visit函数是: Status PrintElement(TElemType e) { //输出元素e的值 printf(e); return OK; } • 调用实例: PreOrderTraverse(T, PrintElement)

More Related