数据结构与算法 第八章 查找
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
因为:
ASL= PiCi
i=1
n
1 在等概率查找的情况下: Pi n
1 n n 1 ASLss (n i 1 ) n i 1 2
对顺序表而言:Ci = n-i+1 顺序表查找成功的平均查找长度为:
顺序表查找不成功的平均查找长度为: ASLus=n+1
所以,顺序表查找的时间复杂度为:O(n)
6 3 1 2 4 7 9 10 8 11
判定树
5
一般情况, 表长为 n 的折半查找判定树的深 度和含有 n 个结点的完全二叉树的深度相同。 假设 n=2h-1 并且查找概率相等
1 n 1 h n 1 则 ASL j 1 Ci n j 2 n log2 (n 1) 1 bs n i 1 j 1 当n>50时近似为
3、查找
根据某个给定值, 在列表中确定其关 键字等于给定值的数据元素(记录)的过程 称为查找。 若列表中存在待查记录, 则称“查找成 功”。查找结果给出整个记录的信息, 或指 示该记录在列表中的位臵;
若列表中不存在待查纪录, 则称“查找不
成功”. 查找结果给出“空记录”或“空指 针”。
4、查找表的分类
24 12 28 53 90
45
所以,二叉排序树 的形态完全由一个 输入序列决定,一 个无序序列可以通 过构造一棵二叉排 序树而得到一个有 序序列
五、二叉排序树的查找性能
对于一组相同的关键字序列,关键字插入的先后次 序不同,所构成的二叉排序树的形态及深度也不同。 二叉排序树的平均查找长度ASL与二叉排序树的形 态有关:二叉排序树的各分支越均衡,树的深度越浅, 其平均查找长度ASL越小。 例如:
(1)k=t:则查找成功,返回根结点地址;
(2)k<t:则进一步查左子树; (3)k>t:则进一步查右子树。 显然这是一个递归过程,可用递归算法 实现查找。
例如: 二叉排序树
50
30
20 35 32 查找关键字 == 50 , 35 , 90 , 95 , 40
80
90 85
88
从上述查找过程可见:
45 24 12 37 53 93
12 24 37 45 53
(b)输入关键字序列为
(a) 输入关键字序列为 {45,24,53,12,37,93}时的二叉排序树
93
{12,24,37,45,53,93}时的二叉排序树
22 设 key = 48
T f
f T f
Tf
f f Tp T
30
T f
20
40
10
T
Tp
f
25
35
23
二叉排序树的生成
给定一个元素序列,将二叉排序 树初始化为一棵空树,然后逐个读入
元素,每读入一个元素,就将新元素
插入当前已生成的二叉排序树中,直 至元素序列插入完毕。
例如: 元素输入序列为:45,24,53,12,28,90,
i
9 10 11 n
i
56 21 37 88 19 92 5 64 56 80 75 13 … 9
结果: i = 8 i
0 1 2
k=60
i
4 5 6 7 8 9 10 11 n
60 21 37 88 19 92 5 64 56 80 75 13 … 9
3
结果: i = 0
3、顺序查找的时间复杂度分析
在查找过程中,生成了一条查找路径:
从根结点出发,沿着左分支或右分支逐层 向下直至关键字等于给定值的结点;
或者
——查找成功
从根结点出发,沿着左分支或右分支逐层 向下直至指针指向空树为止。 ——查找不成功
三、插入
已知关键字值为Key的结点由s指示,将其 插入二叉排序树的过程为: 1、若二叉排序树为空树,则s成为二叉排序树 的根; 2、若二叉树排序树非空,则将key与二叉树排 序树根结点的值t进行比较,如果: (1)key=t:不进行插入; (2)key<t:则将s插入左子树; (3)key>t:则将s插入右子树。 显然,可以用递归算法实现插入。
2)动态查找表:不仅作查询和检索操作,还 经常进行插入和删除操作的列表。
1)静态查找表:仅作查询和检索操作的列表。
在查找算法中要用到三类参量,即: ①查找对象K(找什么) ②查找范围L(在哪找) ③查找的结果(K在L中的位置) 其中①②为输入参量,在函数中不可缺少; ③为输出参量,可用函数返回值表示。
可以证明:当s=√n 时,ASL取最小值√n+1 . 折半查找索引时:ASL=log2(n/s+1)+s/2
8.3 基于树的查找法
一、二叉排序树
二、平衡二叉排序树(略)
8. 3. 1 二叉排序树(二叉查找树)
一、定义
二、查找
三、插入
四、删除(略)
五、性能分析
一、定义:
二叉排序树:或者是一棵空树,或者是具 有如下特性的二叉树:
设臵监视哨的顺序查找算法
int SeqSearch(SSTable l, KeyType k) { l.elem[0].key=k; i=l.length; while (l.elem[i].key!=k) i--; return(i); } l.r[0]为监视哨,可以防止越界。
例: k=56
0 1 2 3 4 5 6 7 8
第八章 查找
8.1 查找的基本概念
8.2 基于线性表的查找法 8.3 基于树的查找法
8.4 计算式查找---哈希法
8.1 查找的基本概念
1、 列表(查找表):是由同一类型的数据元
素(或记录)构成的集合, 可由任意数据 结构实现。
2、关键字: 数据元素中某数据项的值, 用
以标识(识别)一个(组)数据元素(记录)。 若关键字可以唯一的识别一个记录, 则称之为“主关键字”;若关键字识别的 记录不唯一,则称之为“次关键字”。
5、平均查找长度
为确定数据元素在列表中的位置,需和给 定值进行比较的关键字个数的期望值,称为查 找算法在查找成功时的平均查找长度。 对于长度为n的列表,查找成功时的平均 查找长度为:
n ASL=P1C1+ P2C2+…+ PnCn = PiCi i=1
其中:Pi为查找列表中第i个数据元素的概率, Ci为找到列表中第i个数据元素时,已经 进行过的关键字比较次数。
可见: 索引顺序表查找的过程也是一个
“缩小区间”的查找过程。 索引可以根据查找表的特点来构造。
分块查找时间复杂度分析
分块查找的平均查找长度 = 查找“索引”的平均查找长度 + “块内” 查找的平均查找长度 若n个记录分为b块,每块含s个记录, 则等概率情况下, 顺序查找索引时: ASL=(b+1)/2+(s+1)/2 =(n/s+s)/2+1
ASLbslog2(n+1)-1
最坏情况查找长度为二叉树的深度:log2n +1
查找不成功时的比较次数最多也为:log2n +2
所以,折半查找的时间复杂度为:O(log n)
三、分块查找法(索引顺序表查找)
分块查找要将列表组织成以下索引顺序结构: ★首先将列表分成若干个块(子表),一般情况下 块的长度均匀,最后一块可以不满。每块中元 素任意排列(块内无序),但块与块之间有序。 ★构造一个索引表,其中每个索引项对应一个块, 记录每块的起始位臵及每块中的最大关键字 (或最小关键字)。索引表按关键字有序排列。
按上述算法生成的二叉排序树的过程:
45
45 24
空树 插入45
45
24
插入53
53
插入24
45 24 12
插入12
45 53 12 24 28
插入28
Leabharlann Baidu
45 53 12 24 28
插入90
53 90
对同样一组元素值,如果输入的顺序不同, 所建的二叉排序树形态也不同。
如将上述关键字顺序变为:24,53,90,12,28,45, 则生成的二叉排序树为:
6、查找的基本方法:
基于线性表的查找法
比较式 查找法 查找方法:
基于树的查找法 计算式查找法-HASH(哈希)查找法
8.2 基于线性表的查找法
有顺序查找、折半查找和分块查找法三种
一、顺序查找法
顺序查找的特点是:用所给关键字与线性表 中各元素的关键字逐个比较,直到成功或失败。 顺序结构 存储结构: 链式结构
二叉排序树的存储结构 通常用二叉链表作为二叉排 序树的存储结构
typedef struct node { KeyType key ;
…… /*关键字的值*/
struct node *lchild,*rchild;/*左右指针*/ }bstnode,*BSTree;
二、查找
根据二叉排序树的特点,查找过程如下: 若二叉排序树为空,则查找不成功;否则将 待查关键字k与根结点关键字t进行比较,如果:
二、折半查找法(二分搜索法)
1、概念 条件:要求待查找的列表必须是按关键 字大小有序排列的顺序表。 查找方法:由于列表是按关键字有序排 列,所以可以基于“折半确定区间”的 思想进行查找。 优点:比较次数少,查找速度快; 缺点:要求表为有序表,插入、删除困难。
例如:
k=64 的查找过程如下:
n
05 13 19 21 37 56 64 75 80 88 92
整个表由两部分组成:基本块表与索引表。
例:
索 引 表 各块最大关键字 各块起始地址 22 48 86 1 6 12
22 12 13 8 9 33 42 38 24 48 28 74 49 … 1 2 3 4 5 6 7 8 9 10 11 12 13…
分块查找过程
1)由索引确定记录所在的块(折半或顺序查); 2)在块内进行查找(顺序查)。
int
length; // 表的长度
} SSTable;
顺序查找过程示例:
i i i i
0 1 2 3 4 5
i i i
6 7 8 9 10 11
或 i
n
21 37 88 19 92 5 64 56 80 75 13 … 9
假设给定值 k=64, 要求 elem[i].key=k, 问: i = ?结果: i = 7
1、顺序结构数据类型定义:
数据元素类型的定义为:
typedef struct { keyType key; …… } ElemType ; // 关键字域 // 其它属性域
假设静态查找表的顺序存储结构为 typedef struct { ElemType elem[MaxSize]; // 数据元素存储空间基址,建表时 // 按实际长度分配,0号单元留空
(1)若左子树不空,则左子树上所有结 点的值均小于根结点的值; (2)若右子树不空,则右子树上所有结 点的值均大于根结点的值;
(3)左、右子树也分别为二叉排序树。
例如: 30
20 10 25 35
50
80
40 66 85 90
23
不 是二叉排序树。
88
*
中序遍历一个二叉排序树,可以得到一 个递增有序序列。
3、折半查找时间复杂度分析
1. 找到有序表中任一记录的过程就是走了一条 先看一个具体的情况,假设:n=11 ASLsuccss = (11+22+43+44)/11=33/11
i 从根结点到与该记录相应的结点的路径, 11 1 2 3 4 5 6 7 ASLunsucc= (44+85)/12=56/12 8 9 10 2. 给定值进行比较的关键字个数恰是该结点在 Ci判定树上的层次数。 1 3 4 2 3 4 3 4 2 3 4 折半查找的判定树是唯一的。
0 1 2 3 4 5 6 7 8 9 10 11 high
low
low high mid mid mid
low :指示查找区间的下界 high :指示查找区间的上界 mid = (low+high)/2: 每次比较、划分区 间的“点”
2、折半查找算法
int BinSrch (SqList l, KeyType k) { low=1 ; high=l.length; /*置区间初值*/ while ( low<=high) {mid=(low+high) / 2; if (k==l.elem[mid]. key) return(mid); /*找到待查元素*/ else if (k<l.elem[mid]. key) high=mid-1; /*继续在前半区间查找*/ else low=mid+1; /*继续在后半区间查找*/ } return (0); }
2、顺序查找算法
int SeqSearch(SSTable l, KeyType k) { i=l.length; while (i>=1&&l.elem[i].key!=k) i--; if (i>=1) return(i)else return (0); } 循环条件i>=1判断查找是否越界。
ASL= PiCi
i=1
n
1 在等概率查找的情况下: Pi n
1 n n 1 ASLss (n i 1 ) n i 1 2
对顺序表而言:Ci = n-i+1 顺序表查找成功的平均查找长度为:
顺序表查找不成功的平均查找长度为: ASLus=n+1
所以,顺序表查找的时间复杂度为:O(n)
6 3 1 2 4 7 9 10 8 11
判定树
5
一般情况, 表长为 n 的折半查找判定树的深 度和含有 n 个结点的完全二叉树的深度相同。 假设 n=2h-1 并且查找概率相等
1 n 1 h n 1 则 ASL j 1 Ci n j 2 n log2 (n 1) 1 bs n i 1 j 1 当n>50时近似为
3、查找
根据某个给定值, 在列表中确定其关 键字等于给定值的数据元素(记录)的过程 称为查找。 若列表中存在待查记录, 则称“查找成 功”。查找结果给出整个记录的信息, 或指 示该记录在列表中的位臵;
若列表中不存在待查纪录, 则称“查找不
成功”. 查找结果给出“空记录”或“空指 针”。
4、查找表的分类
24 12 28 53 90
45
所以,二叉排序树 的形态完全由一个 输入序列决定,一 个无序序列可以通 过构造一棵二叉排 序树而得到一个有 序序列
五、二叉排序树的查找性能
对于一组相同的关键字序列,关键字插入的先后次 序不同,所构成的二叉排序树的形态及深度也不同。 二叉排序树的平均查找长度ASL与二叉排序树的形 态有关:二叉排序树的各分支越均衡,树的深度越浅, 其平均查找长度ASL越小。 例如:
(1)k=t:则查找成功,返回根结点地址;
(2)k<t:则进一步查左子树; (3)k>t:则进一步查右子树。 显然这是一个递归过程,可用递归算法 实现查找。
例如: 二叉排序树
50
30
20 35 32 查找关键字 == 50 , 35 , 90 , 95 , 40
80
90 85
88
从上述查找过程可见:
45 24 12 37 53 93
12 24 37 45 53
(b)输入关键字序列为
(a) 输入关键字序列为 {45,24,53,12,37,93}时的二叉排序树
93
{12,24,37,45,53,93}时的二叉排序树
22 设 key = 48
T f
f T f
Tf
f f Tp T
30
T f
20
40
10
T
Tp
f
25
35
23
二叉排序树的生成
给定一个元素序列,将二叉排序 树初始化为一棵空树,然后逐个读入
元素,每读入一个元素,就将新元素
插入当前已生成的二叉排序树中,直 至元素序列插入完毕。
例如: 元素输入序列为:45,24,53,12,28,90,
i
9 10 11 n
i
56 21 37 88 19 92 5 64 56 80 75 13 … 9
结果: i = 8 i
0 1 2
k=60
i
4 5 6 7 8 9 10 11 n
60 21 37 88 19 92 5 64 56 80 75 13 … 9
3
结果: i = 0
3、顺序查找的时间复杂度分析
在查找过程中,生成了一条查找路径:
从根结点出发,沿着左分支或右分支逐层 向下直至关键字等于给定值的结点;
或者
——查找成功
从根结点出发,沿着左分支或右分支逐层 向下直至指针指向空树为止。 ——查找不成功
三、插入
已知关键字值为Key的结点由s指示,将其 插入二叉排序树的过程为: 1、若二叉排序树为空树,则s成为二叉排序树 的根; 2、若二叉树排序树非空,则将key与二叉树排 序树根结点的值t进行比较,如果: (1)key=t:不进行插入; (2)key<t:则将s插入左子树; (3)key>t:则将s插入右子树。 显然,可以用递归算法实现插入。
2)动态查找表:不仅作查询和检索操作,还 经常进行插入和删除操作的列表。
1)静态查找表:仅作查询和检索操作的列表。
在查找算法中要用到三类参量,即: ①查找对象K(找什么) ②查找范围L(在哪找) ③查找的结果(K在L中的位置) 其中①②为输入参量,在函数中不可缺少; ③为输出参量,可用函数返回值表示。
可以证明:当s=√n 时,ASL取最小值√n+1 . 折半查找索引时:ASL=log2(n/s+1)+s/2
8.3 基于树的查找法
一、二叉排序树
二、平衡二叉排序树(略)
8. 3. 1 二叉排序树(二叉查找树)
一、定义
二、查找
三、插入
四、删除(略)
五、性能分析
一、定义:
二叉排序树:或者是一棵空树,或者是具 有如下特性的二叉树:
设臵监视哨的顺序查找算法
int SeqSearch(SSTable l, KeyType k) { l.elem[0].key=k; i=l.length; while (l.elem[i].key!=k) i--; return(i); } l.r[0]为监视哨,可以防止越界。
例: k=56
0 1 2 3 4 5 6 7 8
第八章 查找
8.1 查找的基本概念
8.2 基于线性表的查找法 8.3 基于树的查找法
8.4 计算式查找---哈希法
8.1 查找的基本概念
1、 列表(查找表):是由同一类型的数据元
素(或记录)构成的集合, 可由任意数据 结构实现。
2、关键字: 数据元素中某数据项的值, 用
以标识(识别)一个(组)数据元素(记录)。 若关键字可以唯一的识别一个记录, 则称之为“主关键字”;若关键字识别的 记录不唯一,则称之为“次关键字”。
5、平均查找长度
为确定数据元素在列表中的位置,需和给 定值进行比较的关键字个数的期望值,称为查 找算法在查找成功时的平均查找长度。 对于长度为n的列表,查找成功时的平均 查找长度为:
n ASL=P1C1+ P2C2+…+ PnCn = PiCi i=1
其中:Pi为查找列表中第i个数据元素的概率, Ci为找到列表中第i个数据元素时,已经 进行过的关键字比较次数。
可见: 索引顺序表查找的过程也是一个
“缩小区间”的查找过程。 索引可以根据查找表的特点来构造。
分块查找时间复杂度分析
分块查找的平均查找长度 = 查找“索引”的平均查找长度 + “块内” 查找的平均查找长度 若n个记录分为b块,每块含s个记录, 则等概率情况下, 顺序查找索引时: ASL=(b+1)/2+(s+1)/2 =(n/s+s)/2+1
ASLbslog2(n+1)-1
最坏情况查找长度为二叉树的深度:log2n +1
查找不成功时的比较次数最多也为:log2n +2
所以,折半查找的时间复杂度为:O(log n)
三、分块查找法(索引顺序表查找)
分块查找要将列表组织成以下索引顺序结构: ★首先将列表分成若干个块(子表),一般情况下 块的长度均匀,最后一块可以不满。每块中元 素任意排列(块内无序),但块与块之间有序。 ★构造一个索引表,其中每个索引项对应一个块, 记录每块的起始位臵及每块中的最大关键字 (或最小关键字)。索引表按关键字有序排列。
按上述算法生成的二叉排序树的过程:
45
45 24
空树 插入45
45
24
插入53
53
插入24
45 24 12
插入12
45 53 12 24 28
插入28
Leabharlann Baidu
45 53 12 24 28
插入90
53 90
对同样一组元素值,如果输入的顺序不同, 所建的二叉排序树形态也不同。
如将上述关键字顺序变为:24,53,90,12,28,45, 则生成的二叉排序树为:
6、查找的基本方法:
基于线性表的查找法
比较式 查找法 查找方法:
基于树的查找法 计算式查找法-HASH(哈希)查找法
8.2 基于线性表的查找法
有顺序查找、折半查找和分块查找法三种
一、顺序查找法
顺序查找的特点是:用所给关键字与线性表 中各元素的关键字逐个比较,直到成功或失败。 顺序结构 存储结构: 链式结构
二叉排序树的存储结构 通常用二叉链表作为二叉排 序树的存储结构
typedef struct node { KeyType key ;
…… /*关键字的值*/
struct node *lchild,*rchild;/*左右指针*/ }bstnode,*BSTree;
二、查找
根据二叉排序树的特点,查找过程如下: 若二叉排序树为空,则查找不成功;否则将 待查关键字k与根结点关键字t进行比较,如果:
二、折半查找法(二分搜索法)
1、概念 条件:要求待查找的列表必须是按关键 字大小有序排列的顺序表。 查找方法:由于列表是按关键字有序排 列,所以可以基于“折半确定区间”的 思想进行查找。 优点:比较次数少,查找速度快; 缺点:要求表为有序表,插入、删除困难。
例如:
k=64 的查找过程如下:
n
05 13 19 21 37 56 64 75 80 88 92
整个表由两部分组成:基本块表与索引表。
例:
索 引 表 各块最大关键字 各块起始地址 22 48 86 1 6 12
22 12 13 8 9 33 42 38 24 48 28 74 49 … 1 2 3 4 5 6 7 8 9 10 11 12 13…
分块查找过程
1)由索引确定记录所在的块(折半或顺序查); 2)在块内进行查找(顺序查)。
int
length; // 表的长度
} SSTable;
顺序查找过程示例:
i i i i
0 1 2 3 4 5
i i i
6 7 8 9 10 11
或 i
n
21 37 88 19 92 5 64 56 80 75 13 … 9
假设给定值 k=64, 要求 elem[i].key=k, 问: i = ?结果: i = 7
1、顺序结构数据类型定义:
数据元素类型的定义为:
typedef struct { keyType key; …… } ElemType ; // 关键字域 // 其它属性域
假设静态查找表的顺序存储结构为 typedef struct { ElemType elem[MaxSize]; // 数据元素存储空间基址,建表时 // 按实际长度分配,0号单元留空
(1)若左子树不空,则左子树上所有结 点的值均小于根结点的值; (2)若右子树不空,则右子树上所有结 点的值均大于根结点的值;
(3)左、右子树也分别为二叉排序树。
例如: 30
20 10 25 35
50
80
40 66 85 90
23
不 是二叉排序树。
88
*
中序遍历一个二叉排序树,可以得到一 个递增有序序列。
3、折半查找时间复杂度分析
1. 找到有序表中任一记录的过程就是走了一条 先看一个具体的情况,假设:n=11 ASLsuccss = (11+22+43+44)/11=33/11
i 从根结点到与该记录相应的结点的路径, 11 1 2 3 4 5 6 7 ASLunsucc= (44+85)/12=56/12 8 9 10 2. 给定值进行比较的关键字个数恰是该结点在 Ci判定树上的层次数。 1 3 4 2 3 4 3 4 2 3 4 折半查找的判定树是唯一的。
0 1 2 3 4 5 6 7 8 9 10 11 high
low
low high mid mid mid
low :指示查找区间的下界 high :指示查找区间的上界 mid = (low+high)/2: 每次比较、划分区 间的“点”
2、折半查找算法
int BinSrch (SqList l, KeyType k) { low=1 ; high=l.length; /*置区间初值*/ while ( low<=high) {mid=(low+high) / 2; if (k==l.elem[mid]. key) return(mid); /*找到待查元素*/ else if (k<l.elem[mid]. key) high=mid-1; /*继续在前半区间查找*/ else low=mid+1; /*继续在后半区间查找*/ } return (0); }
2、顺序查找算法
int SeqSearch(SSTable l, KeyType k) { i=l.length; while (i>=1&&l.elem[i].key!=k) i--; if (i>=1) return(i)else return (0); } 循环条件i>=1判断查找是否越界。