二叉树与平衡二叉树实现资料讲解
二叉排序树

②若*p结点只有左子树,或只有右子树,则可将*p的左子 树或右子树直接改为其双亲结点*f的左子树,即: f->1child=p->1child(或f->1child=p->rchild); free(p); *f
F *p P P1
*f
F
*f
F *p P
*f
F
Pr
P1
Pr
③若*p既有左子树,又有右子树。则:
-1 0
47
-1
47
47
0
31 69
69
25
0
47
0
25
0
47
-1 0
31
0
69
0
40
69
40
69
0
25 76
40
76
(a)
AL、BL、BR 都是空树
(b) AL、BL、BR 都是非空树
LR型调整操作示意图
2
A
-1
0
C
AR C BL CL CR AR
0 0
B BL CL S
B
A
CR
(a) 插入结点*s后失去平衡
31
0 0 -1
31
0 1
28
0
25
0 0
47
0
25
-1
47
0
25
0
31
0
16 0
28
16
28
0
16 30
30
47
(c) LR(R)型调整
RL型调整操作示意图
A B C A BR CR B BR
AL
C
AL
CL CR
二叉树概述

=0.xx =1; 若结点个数n=3,则有深度k=1,满足k=lb(3+1)-1=1。
二叉树概述
1.二叉树的定义
一、二叉树:是n(n≥0)个结点的有限集合。n=0的树称为空二叉树;n>0的二叉树由 一个根结点以及两棵互不相交的、分别称为左子树和右子树的二叉树组成 。
逻辑结构: 一对二(1:2) 基本特征: ① 每个结点最多只有两棵子树(不存在度大于2的结点); ② 左子树和右子树次序不能颠倒。所以下面是两棵不同的树 注意:二叉树不是有序树
3.二叉树的性质
性质1 在一棵非空二叉树的第i层上至多有2i个结点(i≥0)。
性质2 深度为k的二叉树至多有2k+1-1个结点。 说明:深度k=-1,表示没有一个结点;深度k=0,表示只有一个根结点。
性质3 对于一棵非空的二叉树,如果叶结点个数为n0,度为2的结点数为n2, 则有 n0= n2+1。 证明:设n为二叉树的结点总数,n1为二叉树中度为1的结点个数,则有: n = n0 + n1 + n2
A
B
C
D
E
F
G
H I J K L MN O
A
B
C
D
E
F
G
H IJ
(a)满二叉树
(b)完全二叉树
问题:一个高度为h的完全二叉树最多有多少个结点?最少有多少个结点?
数据结构——- 二叉树

证明: 5.1 二叉树的概念
(1)总结点数为 ●二叉树的主要性质 n=n0+n1+n2 (2)除根结点外,每个 ●性质3: 结点都有一个边e进入 任何一棵二叉树,若其终端结点数为n0, n=e+1 度为2的结点数为n2,则n0=n2+1 (3)边e又是由度为1或2 A 的点射出,因此 e=n1+2n2 G B (4)由(2)(3) F C D n=n1+2n2+1 (5)由(4)-(1)可得 G n0=n2+1
《数据结构与算法》
★★★★★
第五章 二叉树
廊坊师范学院 数学与信息科学学院
树型结构--实例:五子棋
A
B
D
E
F
C
…...........
…...........
第五章 二叉树
本章重点难点
重点: 二叉树的定义,性质,存储结 构以及相关的应用——遍历,二叉搜 索树,堆优先 队列,Huffman树等 难点: 二叉树的遍历算法及相关应用
证明: 5.1 二叉树的概念
(1)总结点数为 ●二叉树的主要性质 n=n0+n1+n2 (2)除根结点外,每个 ●性质3: 结点都有一个边e进入 任何一棵二叉树,若其终端结点数为n0, n=e+1 度为2的结点数为n2,则n0=n2+1 (3)边e又是由度为1或2 A 的点射出,因此 e=n1+2n2 G B (4)由(2)(3) F C D n=n1+2n2+1 (5)由(4)-(1)可得 G n0=n2+1
A B C E D F G
证明: 由性质4可推出
由性质2(深度为k的 二叉树,至多有2k+1-1 个结点)可知,高度 为h(k+1)的二叉树,其 有n (n>0)个结点的完全二叉树的高度为 结点个数n满足: 「log2(n+1) ,深度为「log2(n+1) -1 2h-1-1<n<=2h-1 高度:二叉树中最大叶结点的层数+1 2h-1<n+1<=2h 取对数得到: 0层 1 h-1<log2(n+1)<=h 3 1层 2 因为h是整数,所以 h= log2(n+1) 5 2层 4
树的种类和构造

树的种类和构造树是一种重要的数据结构,它具有分层结构和层次性的特点。
在计算机科学中,树的种类和构造非常丰富多样。
本文将介绍一些常见的树的种类和它们的构造方式,以及它们在实际应用中的一些应用场景。
一、二叉树二叉树是最简单、也是最常见的一种树结构,它由一个根节点以及每个节点最多有两个子节点组成。
二叉树的构造方式有多种,包括满二叉树、完全二叉树、平衡二叉树等。
其中,满二叉树是一种特殊的二叉树,每个节点要么没有子节点,要么有两个子节点;完全二叉树是一种二叉树,除了最后一层的叶子节点外,其他层的节点都是满的;平衡二叉树是一种二叉树,它的左子树和右子树的高度差不超过1。
二叉树的应用非常广泛,例如在搜索算法中,二叉搜索树可以快速地定位某个节点;在编译原理中,语法分析树可以用于解析和分析代码的结构;在图像处理中,霍夫曼树可以用于对图像进行压缩等。
二、多叉树多叉树是一种每个节点最多有多个子节点的树结构。
它的构造方式和二叉树不同,可以有任意多个子节点。
多叉树的应用也非常广泛,例如在文件系统中,目录和文件的关系可以用多叉树来表示;在组织架构中,公司的部门和员工的关系也可以用多叉树来表示。
三、红黑树红黑树是一种自平衡的二叉查找树,它在插入和删除节点时会自动调整树的结构,保持树的平衡性。
红黑树的构造方式非常复杂,但它的性能非常优秀,能够在最坏情况下保持对数时间的复杂度。
红黑树的应用非常广泛,例如在C++的STL中,红黑树被用于实现set 和map等容器。
四、B树B树是一种自平衡的多路查找树,它的每个节点可以存储多个键值对。
B树的构造方式和红黑树类似,但它的每个节点可以有多个子节点。
B树的应用非常广泛,特别适合在磁盘等外存储设备上进行查找和插入操作,因为它可以最大限度地减少磁盘的I/O操作次数。
五、Trie树Trie树,也称为字典树或前缀树,是一种用于快速检索字符串的树结构。
它的每个节点包含一个字符,根节点表示空字符。
Trie树的构造方式非常简单,每个字符对应一个子节点。
数学 树的种类

数学树的种类数学中的树是一种常见的数学结构,它在计算机科学、图论和离散数学等领域有着广泛的应用。
树是由节点和边组成的,节点之间的关系是一种层次结构,每个节点可以有多个子节点,但只能有一个父节点。
树可以分为不同的种类,每种树都有其特殊的性质和应用。
一、二叉树二叉树是一种特殊的树结构,每个节点最多只能有两个子节点,分别称为左子节点和右子节点。
二叉树的特点是每个节点的子节点有且只有两个,且子节点的顺序是固定的。
二叉树的遍历方式包括前序遍历、中序遍历和后序遍历。
二叉树的应用非常广泛,例如在排序算法中的二叉搜索树、哈夫曼树等。
二、平衡树平衡树是一种特殊的二叉树,它的每个节点的左右子树的高度差不超过1。
平衡树的设计旨在保持树的平衡,使得树的高度尽可能小,从而提高树的查询效率。
常见的平衡树包括AVL树、红黑树等。
平衡树的插入和删除操作会通过旋转操作来保持树的平衡。
三、B树B树是一种多叉树,每个节点可以包含多个子节点。
B树的特点是每个节点可以存储多个元素,并且元素是有序的。
B树的应用非常广泛,特别适用于在磁盘等外部存储设备上进行数据管理,例如文件系统、数据库索引等。
四、二叉堆二叉堆是一种特殊的二叉树,它满足堆的性质,即父节点的值总是小于或等于子节点的值。
二叉堆可以用来实现优先队列等数据结构,常见的操作包括插入和删除最小元素。
二叉堆可以通过数组来实现,具有较高的效率和较小的空间复杂度。
五、树状数组树状数组是一种特殊的数据结构,用于高效地计算前缀和。
树状数组可以用来解决一类问题,例如统计数组中某个区间的元素和、求逆序对数等。
树状数组的主要操作包括更新和查询,它的时间复杂度都是O(logn)。
六、Trie树Trie树,也称为字典树或前缀树,是一种用于高效存储和查找字符串的数据结构。
Trie树的每个节点表示一个字符,从根节点到叶子节点的路径表示一个字符串。
Trie树的特点是可以快速地查找具有相同前缀的字符串,常见的应用包括字典、搜索引擎等。
数据结构树和二叉树知识点总结

数据结构树和二叉树知识点总结
1.树的概念:树是一种非线性的数据结构,由节点和边构成,每个节点只能有一个父节点,但可以有多个子节点。
2. 二叉树的概念:二叉树是一种特殊的树结构,每个节点最多只有两个子节点,一个是左子节点,一个是右子节点。
3. 二叉树的遍历:二叉树的遍历分为前序遍历、中序遍历和后序遍历三种方式。
前序遍历是先访问根节点,再访问左子树,最后访问右子树;中序遍历是先访问左子树,再访问根节点,最后访问右子树;后序遍历是先访问左子树,再访问右子树,最后访问根节点。
4. 二叉搜索树:二叉搜索树是一种特殊的二叉树,它满足左子树中所有节点的值均小于根节点的值,右子树中所有节点的值均大于根节点的值。
因此,二叉搜索树的中序遍历是一个有序序列。
5. 平衡二叉树:平衡二叉树是一种特殊的二叉搜索树,它的左子树和右子树的高度差不超过1。
平衡二叉树的插入和删除操作可以保证树的平衡性,从而提高树的查询效率。
6. 堆:堆是一种特殊的树结构,它分为最大堆和最小堆两种。
最大堆的每个节点的值都大于等于其子节点的值,最小堆的每个节点的值都小于等于其子节点的值。
堆常用于排序和优先队列。
7. Trie树:Trie树是一种特殊的树结构,它用于字符串的匹配和检索。
Trie树的每个节点代表一个字符串的前缀,从根节点到叶子节点的路径组成一个完整的字符串。
以上是数据结构树和二叉树的一些基本知识点总结,对于深入学
习数据结构和算法有很大的帮助。
C语言数据结构系列篇二叉树的概念及满二叉树与完全二叉树
C语⾔数据结构系列篇⼆叉树的概念及满⼆叉树与完全⼆叉树链接:0x00 概念定义:⼆叉树既然叫⼆叉树,顾名思义即度最⼤为2的树称为⼆叉树。
它的度可以为 1 也可以为 0,但是度最⼤为 2 。
⼀颗⼆叉树是节点的⼀个有限集合,该集合:①由⼀个根节点加上两颗被称为左⼦树和右⼦树的⼆叉树组成②或者为空观察上图我们可以得出如下结论:①⼆叉树不存在度⼤于 2 的节点,换⾔之⼆叉树最多也只能有两个孩⼦。
②⼆叉树的⼦树有左右之分,分别为左孩⼦和右孩⼦。
次序不可颠倒,因此⼆叉树是有序树。
注意:对于任意的⼆叉树都是由以下⼏种情况复合⽽成的:0x01 满⼆叉树定义:⼀个⼆叉树,如果每⼀层的节点数都达到了最⼤值(均为2),则这个⼆叉树就可以被称作为 "满⼆叉树" 。
换⾔之,如果⼀个⼆叉树的层数为,且节点总数是,则他就是⼀个满⼆叉树。
计算公式:①已知层数求总数:②已知总数求层数:⼗亿个节点,满⼆叉树是多少层?≈ 10亿多0x02 完全⼆叉树定义:对于深度为的,有个结点的⼆叉树,当且仅当其每⼀个结点都与深度为的满⼆叉树中编号从 1 ⾄的结点⼀⼀对应时称之为完全⼆叉树。
前层是满的,最后⼀层不满,但是最后⼀层从左到右是连续的。
完全⼆叉树是效率很⾼的数据结构,完全⼆叉树是由满⼆叉树⽽引出来的。
所以,满⼆叉树是⼀种特殊的完全⼆叉树(每⼀层节点均为2)。
常识:①完全⼆叉树中,度为 1 的最多只有 1 个。
②⾼度为的完全⼆叉树节点范围是0x03 ⼆叉树的性质①若规定根节点的层数为 1 ,则⼀颗⾮空⼆叉树的第层上最多有个节点。
②若规定根节点的层数为 1 ,则深度为的⼆叉树最⼤节点数是 .③对任何⼀颗⼆叉树,如果度为 0 其叶⼦结点个数为,度为 2 的分⽀节点个数为,则有。
换⾔之,度为 0 的永远⽐度为 2 的多⼀个叶⼦结点。
④若规定根节点的层数为 1 ,具有个节点的满⼆叉树的深度(log是以2为底,n+1的对数)。
对于有个节点的完全⼆叉树,如果按照从上⾄下从左⾄右的数组顺序对所有节点从 0 开始编号,则对于序号为的节点有:(⾮完全⼆叉树,也可以⽤数组存放,但会浪费很多空间)假设是⽗节点在数组中的下标,此公式仅适⽤于完全⼆叉树:①求左孩⼦:②求右孩⼦:③求⽗亲(假设不关注是左孩⼦还是右孩⼦):④判断是否有左孩⼦:⑤判断是否由右孩⼦:PS:⼆叉树不⼀定要标准,⽐如这个其实也是⼆叉树:课后练习:1. 某⼆叉树共有 399 个结点,其中有 199 个度为 2 的结点,则该⼆叉树中的叶⼦结点数为()A. 不存在这样的⼆叉树B. 200C. 1982. 在具有 2n 个结点的完全⼆叉树中,叶⼦结点个数为()A. nB. n+1C. n-1D. n/23. ⼀棵完全⼆叉树的节点数位为531个,那么这棵树的⾼度为()A. 11B. 10C. 8D. 125. ⼀个具有767个节点的完全⼆叉树,其叶⼦节点个数为()A. 383B. 384C. 385D. 386参考资料:Microsoft. MSDN(Microsoft Developer Network)[EB/OL]. []. .笔者:王亦优更新: 2021.11.24勘误:⽆声明:由于作者⽔平有限,本⽂有错误和不准确之处在所难免,本⼈也很想知道这些错误,恳望读者批评指正!本篇完。
【数据结构】二叉树
【数据结构】⼆叉树【⼆叉树】 ⼆叉树是最为简单的⼀种树形结构。
所谓树形结构,其特征(部分名词的定义就不明确给出了,毕竟不是学术⽂章。
)在于: 1. 如果是⾮空的树形结构,那么拥有⼀个唯⼀的起始节点称之为root(根节点) 2. 除了根节点外,其他节点都有且仅有⼀个“⽗节点”;除此外这些节点还都可以有0到若⼲个“⼦节点” 3. 树中的所有节点都必须可以通过根节点经过若⼲次后继操作到达 4. 节点之间不会形成循环关系,即任意⼀个节点都不可能从⾃⾝出发,经过不重复的径路再回到⾃⾝。
说明了树形结构内部蕴含着⼀种“序”,但是不是线性表那样的“全序” 5. 从树中的任意两个节点出发获取到的两个任意⼦树,要不两者⽆交集,要不其中⼀者是另⼀者的⼦集 限定到⼆叉树,⼆叉树就是任意⼀个节点⾄多只能有两个⼦节点的树形结构。
也就是说,某个节点的⼦节点数可以是0,1或2。
由于可以有两个⼦节点,所以区别两个⼦节点可以将其分别定义为左⼦节点和右⼦节点。
但是需要注意的是,若⼀个节点只有⼀个⼦节点,那么也必须明确这个⼦节点是左⼦节点还是右⼦节点。
不存在“中⼦节点”或者“单⼦节点”这种表述。
由于上述规则对所有节点都⽣效,所以⼆叉树也是⼀个递归的结构。
事实上,递归就是⼆叉树⼀个⾮常重要的特点,后⾯还会提到很多通过递归的思想来建⽴的例⼦。
对于左⼦节点作为根节点的那颗⼆叉树被称为相对本节点的左⼦树,右⼦树是同理。
■ 基本概念 空树 不包含任何节点的⼆叉树,连根节点也没有 单点树 只包含⼀个根节点的⼆叉树是单点树 ⾄于兄弟关系,⽗⼦关系,长辈后辈关系是⼀⾔既明的就不说了。
树中没有⼦节点的节点被称为树叶(节点),其余的则是分⽀节点。
⼀个节点的⼦节点个数被称为“度数”。
正如上所说,⼆叉树任意节点的度数取值可能是0,1或2。
节点与节点之间存在关联关系,这种关联关系的基本长度是1。
通过⼀个节点经过若⼲个关联关系到达另⼀个节点,经过的这些关联关系合起来被称为⼀个路径。
java实现二叉树的基本操作
java实现二叉树的基本操作一、二叉树的定义树是计算机科学中的一种基本数据结构,表示以分层方式存储的数据集合。
树是由节点和边组成的,每个节点都有一个父节点和零个或多个子节点。
每个节点可以对应于一定数据,因此树也可以被视作提供快速查找的一种方式。
若树中每个节点最多只能有两个子节点,则被称为二叉树(Binary Tree)。
二叉树是一种递归定义的数据结构,它或者为空集,或者由一个根节点以及左右子树组成。
如果左子树非空,则左子树上所有节点的数值均小于或等于根节点的数值;如果右子树非空,则右子树上所有节点的数值均大于或等于根节点的数值;左右子树本身也分别是二叉树。
在计算机中实现二叉树,通常使用指针来表示节点之间的关系。
在Java中,定义一个二叉树节点类的代码如下:```public class BinaryTree {int key;BinaryTree left;BinaryTree right;public BinaryTree(int key) {this.key = key;}}```在这个类中,key字段表示该节点的数值;left和right字段分别表示这个节点的左右子节点。
1. 插入节点若要在二叉树中插入一个节点,首先需要遍历二叉树,找到一个位置使得插入新节点后,依然满足二叉树的定义。
插入节点的代码可以写成下面这个形式:```public void insert(int key) {BinaryTree node = new BinaryTree(key); if (root == null) {root = node;return;}BinaryTree temp = root;while (true) {if (key < temp.key) {if (temp.left == null) {temp.left = node;break;}temp = temp.left;} else {if (temp.right == null) {temp.right = node;break;}temp = temp.right;}}}```上面的代码首先创建了一个新的二叉树节点,然后判断二叉树根是否为空,若为空,则将这个节点作为根节点。
05二叉树
}
if (Parent->Lchild == NULL) /* Parent所指结点左子树为空 */ Parent->Lchild = ptr;
else
{
/* Parent所指结点左子树非空 */
ptr->Lchild = Parent->Lchild;
Parent->Lchild = ptr;
}
二叉树可以是空的,空二叉树没有任何结 点; 二叉树上的每个结点最多可以有两棵子树, 这两棵子树是不相交的; 二叉树上一个结点的两棵子树有左、右之 分,次序是不能颠倒的。
图5-2 两棵不同的二叉树
从二叉树中的一个结点往下,到达它的 某个子、孙结点时所经由的路线,称为一条 “路径”。对于路径来说,从开始结点到终 止结点,中间经过的结点个数,称为路径的 “长度”。从根结点开始、到某个结点的路 径长度,称为该结点的“深度”。
一棵一般的二叉树,是由如下的3类结点组成的: 根结点——二叉树的起始结点; 分支(或内部结点)——至少有一个非空子树 (即度为1或2)的结点 叶结点——没有非空子树(即度为0)的结点。 有两种特殊的二叉树:满二叉树和完全二叉树。
所谓“满二叉树”,是指该二叉树的每 一个结点,或是有两个非空子树的结点,或 是叶结点,且每层都必须含有最多的结点个 数。
性质5-2 树高为k(k≥0)的二叉树, 最多有2k+1−1个结点。 【证明】由性质5-1可知,在树高为k的 二叉树里,第0层有20个结点,第1层有21个 结点,第2层有22个结点,„„,第k层有2k 个结点。因此,要求出树高为k的二叉树的 结点个数,就是求和:
20 + 21 + 22 +„+ 2k
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
数据结构课程设计(1)
作业A
一、大型作业(课程设计)题目和内容 1.1二叉排序树与平衡二叉排序树基本操作的实现
1.用二叉链表作储存结构
(1) 以回车(’n')为输入结束标志,输入数列 L,生成二叉排序树 T; (2) 对二叉排序树T作中序遍历,输出结果; (3) 计算二叉排序树T的平均查找长度,输出结果; (4) 输入元素x,查找二叉排序树 T,如果存在含x的结点,则删除该结点, 并作中序遍历(执行操作2);否则输出信息“无结点 x”; (5) 判断二叉排序树T是否为平衡二叉树,输出信息“ 0K!” / “ NO”; *(6) 再用数列L,生成平衡二叉排序树 BT:当插入新元素后,发现当前二叉排序树 BT 不是平衡二叉排序树,则立即将它转换成新的平衡二叉排序树 BT; * ( 7) 计算平衡二叉排序树 BT的平均查找长度,输出结果。
2、
用顺序表(一维数组)作存储结构
(1) 以回车(’n')为输入结束标志,输入数列 L,生成二叉排序树 T;
(2) 对二叉排序树T作中序遍历,输出结果;
(3) 计算二叉排序树 T的平均查找长度,输出结果;
(4) 输入元素x,查找二叉排序树 T,如果存在含x的结点, 则删除该结点,并作中序遍
历(执行操作2);否则输出信息“无结点 x”; (5 )判断二叉排序树 T是否为平衡二叉树,输出信息“ 0K!” / “ NO”。 二. 程序中所采用的数据结构及存储结构的说明 程序中的数据采用“树形结构”作为其数据结构。 具体的,我采用的是“二叉排序 树”。 二叉排序树或者是一棵空树,或者是具有下列性质的二叉树: (1)若它的左子 树不空,则左子树上所有结点的值均小于它的根结点的值; (2)若它的右子树不空,则右子 树上所有结点的值均大于它的根结点的值; (3)它的左右子树也分别为二叉排序树。 程序中分别采用了 “二插链表”和“一维数组”作为其存储结构。 二插链表存储结构中二插树的结点由一个数据元素和分别指向其左、右子树的 两个分支构成。如:我的程序中采用的结构是: typedef struct Tno de{ int data; struct Tn ode *lchild,*rchild ;
}*n ode,BST node;
一维数组顺序表存储结构是用一组地址连续的存储单元依次自上而下、自左而右存 储完全二插树上的结点元素,即将完全二叉树上编号为 i的结点元素存储在如上定义的一维 数组中下标为i-1的分量中。利用顺序表作为存储结构: typedef struct { int *data; int len th; }BST;
一维数组存储结构中结点 i的父母亲为|_i/2」,左孩子为2i,右孩子为2i+1. 三. 算法的设计思想 a)二插链表作存储结构:
建立二插排序树采用边查找边插入的方式。 查找函数采用递归的方式进行查找。 如果查找成功则不应再插入原树, 否则返回当前结点的上一个结点。 然后利用插入函数将该 元素插入原树。 对二叉树进行 中序遍历采用递归函数的方式。 在根结点不为空的情况下, 先访问左 子树,再访问根结点,最后访问右子树。 计算二插排序树的平均查找长度时,仍采用类似中序遍历的递归方式, 用s记录 总查找长度,j记录每个结点的查找长度,s置初值为0,采用累加的方式最终得到总查找长 度s。平均查找长度就等于 s/i(i为树中结点的总个数)。 删除结点函数,采用边查找边删除的方式。 如果没有查找到,则不对树做任何的修改; 如果查找到结点,则分四种情况分别进行讨论: 1、该结点左右子树均为空;2、该结点仅左 子树为空;3、该结点仅右子树为空;4、该结点左右子树均不为空。 判断二插排序树是否为 平衡二叉树的函数,也是采用递归函数的方式,分别判定以树 中每个结点为根结点的子树是否为平衡二叉树。 只要有一个子树不为平衡二叉树, 则该树便 不是平衡二叉树。 b) 一维数组作存储结构 :
建立二插排序树,首先用一个一维数组记录下读入的数据, 然后再用边查找边插入的方式将 数据一一对应放在完全二叉树相应的位置,为空的树结点用“ 0”补齐。 中序遍历 二叉树也采用递归函数的方式, 先访问左子树2i,然后访问根结点i,最后访问右子 树2i+1.先向左走到底再层层返回,直至所有的结点都被访问完毕。 计算二插排序树的 平均查找长度 时,采用类似中序遍历的递归方式,用 s记录 总查找长度,j记录每个结点的查找长度,s置初值为0,采用累加的方式最终得到总查找长 度s。平均查找长度就等于 s/i(i为树中结点的总个数)。 删除二插排序树中某个结点,采用边查找边插入的方式,类似重新建立一个一 维数组作为存储新树的空间。 将原数组中的数据一个一个的插入树中, 若遇到需要删除的结 点则不执行插入操作。
判断二插排序树是否为 平衡二叉树 的函数,也是采用递归函数的方式, 分别判定以树中每个 结点为根结点的子树是否为平衡二叉树。 只要有一个子树不为平衡二叉树, 则该树便不是平
衡二叉树。 四、平衡二叉树与未平衡化的二叉树查找效率比较 (1) 对于未平衡化的二叉树:
当先后插入的关键字有序时,构成的二插排序树蜕变为单支树。树的深度为 n,其平均查找
长度为(n+1) /2.这是最差的情况。这种情况下比较关键字的最大次数为 n次。 (2)最好的情况是
建成的树是一棵平衡二叉树。在这种情况下,二插排序树的平均查找长度和 log2(n)成正比。 比较关键字的最大次数为:0.5log "( 5)+ log “ (n+1) -2次(其中"=(1+根号5) /2 )。 (3)那么,平均情况下分析:
假设在含有n(n>=1)个关键字的序列中,i个关键字小于第一个关键字, n-i-1个关
键字大于第一个关键字,则由此构造而得的二插排序树在 n个记录的查找概率相等的情况 下,其平均查找长度为: P(n, i)=[1+i*(P(i)+1)+( n-i-1)(P (n-i-1)+1)]/n 其中P(i)为含有i个结点的二插排序树的平均查找长度,则 P(i)+1为查找左子树中 每个关键字时所用比较次数的平均值, P(n-i-1 )+1为查找右子树中每个关键字时所用比较 次数的平均值。又假设表中n个关键字的排列是“随机”的, 即任一个关键字在序列中将是 第1个,或第2个,…,或第n个的概率相冋,则可对上式从 i等于0至n-1取平均值。最终 会推导出: 当 n>=2时,P (n) <=2( 1 + 1/n ) ln(n) 由此可见,在随机的情况下,二插排序树的平均查找长度和 log (n )是等数量级的。
五、时间复杂度的分析 说明:对时间复杂度的分析,均指在最坏情况下的时间复杂度。 二插链表存储结构中 (1) 查找函数最坏的情况是要找的点正好是二叉树的最深的叶子结点, 此时时 间复杂度=0(n)。 (2) 插入函数最坏的情况是要插入的点正是二叉树的最深的那一支的叶子结 点,此时时间复杂度= 0(n)。 (3) 中序遍历函数,求平均查找长度的函数,删除函数以及判断二插排序树是 否为平衡二叉树的函数,其时间复杂度均与以上情况类似,等于 O (n)。 一维数组顺序表存储结构中: (1) 插入函数最坏的情况是要插入的点正是二叉树的最深的那一支的叶子结 点,此时时间复杂度等于 0 (n)。 (2) 创建函数最坏的情况就是调用插入函数时插入函数遇到最坏的情况。 因 此,创建函数的时间复杂度也等于 0(n)。 (3) 中序遍历函数,求平均查找长度的函数,查找函数,以及判断二插排序 树是否为平衡二叉树的函数,其时间复杂度均与以上情况类似,等于 0(n)。 (4) 删除函数不采用递归手法, 而是采用重新建立一颗不含要删结点的二插 排序树。其时间复杂度=O (n)。 六、源程序清单 (1)二插链表存储结构源程序清单:
#i nclude #i nclude #i nclude typedef struct Tno de{ int data; struct Tnode *lchild,*rchild;
}*no de,BST no de; searchBST (node t,i nt key ,node f,node *p) { if(!t) {*p=f;return (0);} else if(key==t->data) {*p=t;retur n (1);}
else if(keydata) searchBST(t->lchild,key,t,p); else searchBST(t->rchild,key,t,p); }
in sertBST (node *t,i nt key) { n ode p=NULL,s=NULL; if(!searchBST(*t,key,NULL, &p)) {
s=(no de)malloc(sizeof(BST no de)); s->data=key; s->lchild=s->rchild=NULL; if(!p) *t=s; else if(keydata) p->lchild=s;
else p->rchild=s; return (1); } else return (0);
} ino rderTraverse( node *t) { if(*t){ if(in orderTraverse(&( *t)->lchild)) { prin tf("%d ",(*t)->data); if(i no rderTraverse(&( *t)->rchild)); }