查找 (一):静态查找表 (顺序查找、折半查找、分块查找)

作为数据结构的课程笔记,以便查阅。如有出错的地方,还请多多指正!

  • 查找表 (Search Table):由同一类型的数据元素(或记录)构成的集合
  • 静态查找表 (Static Search Table):仅作查询和检索操作的查找表
  • 动态查找表 (Dynamic Search Table)

查找算法的时间复杂度

  • 查找算法的 基本运算 为 被查找元素 x x x 与查找表中元素的比较。因此,查找算法的 时间复杂度 即为 比较次数平均情况下的时间复杂度 A ( n ) A(n) A(n) 可由 平均查找长度 ASL (Average Search Length) 来衡量
    • ASL:为确定记录在表中的位置,需要与给定值进行比较的次数的期望值
    • 对含有 n n n 个记录的表, A S L = ∑ i = 1 n p i c i ASL=\sum_{i=1}^np_ic_i ASL=i=1npici p i p_i pi 为查找表中第 i i i 个元素的概率, c i c_i ci 为找到表中第 i i i 个元素所需比较次数

顺序查找 Sequential Search

查找过程

  • 查找过程:从表的一端开始逐个进行记录的关键字和给定值的比较
  • 适用条件:以顺序表线性链表表示的静态查找表

算法实现

//顺序查找
int Search_seq(SSTable_t* sstable, Key_t key)
{
	int i;

	sstable->rec[0].key = key;
	for (i = sstable->len; sstable->rec[i].key != key; --i)
	{
	}
	return i;
}
  • 第 0 个元素起监视哨的作用。这个改进能使顺序查找在 n ≥ 1000 n\geq1000 n1000 时,进行一次查找的平均时间几乎减半

性能分析

ASL

  • 表中各元素查找概率相等时
    A S L = ∑ i = 1 n p i c i = 1 n ∑ i = 1 n ( n − i + 1 ) = n + 1 2 ASL=\sum_{i=1}^np_ic_i=\frac{1}{n}\sum_{i=1}^n(n-i+1)=\frac{n+1}{2} ASL=i=1npici=n1i=1n(ni+1)=2n+1
  • 表中各元素查找概率不等时
    A S L 在 p n ≥ p n − 1 ≥ . . . ≥ p 2 ≥ p 1 时 取 m i n ASL在p_n\geq p_{n-1} \geq...\geq p_2\geq p_1时取min ASLpnpn1...p2p1min
    因此,若能预知每个记录的查找概率,则应先对记录按查找概率进行升序排序。若查找概率无法事先测定,则可以为记录增设访问频度域,始终保持按访问频度非递减有序排列,使查找概率大的记录不断后移,或每次查找之后将刚查找到的记录直接移至表尾
  • 当查找不成功的情形不能忽视时,假设要查找的元素 x x x L L L 中概率是 p p p, 且每个位置概率相等,则
    A ( n ) = A S L = ∑ i = 1 n i p n + ( 1 − p ) n = p ( n + 1 ) 2 + ( 1 − p ) n A(n)=ASL=\sum_{i=1}^ni\frac{p}{n}+(1-p)n=\frac{p(n+1)}{2}+(1-p)n A(n)=ASL=i=1ninp+(1p)n=2p(n+1)+(1p)n p = 1 2 p=\frac{1}{2} p=21 时, A ( n ) = A S L = 3 n + 1 4 ≈ 3 n 4 A(n)=ASL=\frac{3n+1}{4}\approx\frac{3n}{4} A(n)=ASL=43n+143n

总结

  • 优点:算法简单,对表的逻辑次序和存储结构无要求
  • 缺点:平均查找长度较大

折半查找 Binary Search

查找过程

  • 查找过程:二分法
  • 适用条件:采用顺序存储结构的有序静态查找表

算法实现

  • 需要注意的是,如果二分上界超过 int 型数据范围的一半,那么当欲查询元素在序列较靠后的位置时, 语句 mid = (left + right) / 2 中的 left + right 就有可能超过 int 而导致溢出, 此时一般使用 mid = left + (right - left) / 2 这条等价语句作为代替以避免溢出
int Binary_search(SSTable_t* sstable, Key_t key)
{
	int low = 1;
	int high = sstable->len;
	int mid = (low + high) / 2;

	while (low <= high)
	{
		if (sstable->rec[mid].key < key)
		{
			low = mid + 1;
		}
		else if (sstable->rec[mid].key > key)
		{
			high = mid - 1;
		}
		else {
			return mid;
		}
		mid = (low + high) / 2;
	}
	return 0;
}

性能分析

判定树

  • 判定树:描述查找过程的二叉树。判定树并非完全二叉树,但它的叶结点所在层数之差最多为 1,深度与同样结点数的完全二叉树相同。因此 n n n 个结点的判定树深度为 ⌊ l o g 2 n ⌋ + 1 \lfloor log_2n \rfloor +1 log2n+1
  • 折半查找法的比较次数不超过其判定树的深度,因此折半查找在查找成功时最多进行 ⌊ l o g 2 n ⌋ + 1 \lfloor log_2n \rfloor +1 log2n+1 次关键字比较; 查找不成功时的比较次数为判定树深度 +1
    在这里插入图片描述
    在这里插入图片描述

ASL

  • 设判定树为深度为 h h h 的满二叉树
    A S L = ∑ i = 1 n p i c i = 1 n ∑ j = 1 h j ⋅ 2 j − 1 = n + 1 n l o g 2 ( n + 1 ) − 1 ≈ l o g 2 ( n + 1 ) − 1 ASL=\sum_{i=1}^np_ic_i=\frac{1}{n}\sum_{j=1}^hj\cdot 2^{j-1}=\frac{n+1}{n}log_2(n+1)-1\approx log_2(n+1)-1 ASL=i=1npici=n1j=1hj2j1=nn+1log2(n+1)1log2(n+1)1
  • 在不等概率查找的情况下,折半查找不是有序表查找的最好方法。应使查找概率大的元素更接近判定树的根

总结

  • 优点:平均查找长度较小
  • 缺点:只适用于顺序存储的有序表,不适用于一般顺序表和链式存储结构

证明在每个元素的搜索概率相等时,二分查找效率最高

  • 设有 N N N 个数,一次分割查找后剩下数越少效率越高。设分割比为 x x x 1 − x 1-x 1x,分完后剩 n n n 个数, 则 P ( n = N x ) = x , P ( n = N ( 1 − x ) ) = 1 − x P(n=Nx)=x,P(n=N(1-x))=1-x P(n=Nx)=xP(n=N(1x))=1x
    ∴ E ( n ) = N x ⋅ x + N ( 1 − x ) ⋅ ( 1 − x ) = N ( x 2 + ( 1 − x ) 2 ) \therefore E(n)=Nx\cdot x + N(1-x)\cdot (1-x) = N(x^2+(1-x)^2) E(n)=Nxx+N(1x)(1x)=N(x2+(1x)2)上式在 x = 0.5 x=0.5 x=0.5 时最小,即二分法查找效率最高

分块查找 / 索引顺序查找

查找过程

  • 查找过程:将线性表分成几块,块内无序,块间有序;先确定待查记录所在块,再在块内查找
  • 适用条件:分块有序表

算法实现

  • 建立索引表,每个索引表结点含有一个数据域(本块最大关键字)和一个指针域(指向本块第一个结点)
  • 索引表查找可用顺序、折半查找
  • 块内查找只能用顺序查找
  • 数据可用链式存储
    在这里插入图片描述

性能分析

ASL

  • L b L_b Lb 为查找索引表确定所在块的平均查找长度, L w L_w Lw 为在块中查找元素的平均查找长度
    A S L = L b + L w ASL=L_b+L_w ASL=Lb+Lw将表长为 n n n 的表平均分成 b b b 块,每块含 s s s 个记录,并设表中每个记录的查找概率相等,则
  • 用顺序查找确定所在块
    A S L = b + 1 2 + s + 1 2 ASL=\frac{b+1}{2}+\frac{s+1}{2} ASL=2b+1+2s+1
  • 用折半查找确定所在块
    A S L ≈ l o g 2 ( b + 1 ) + s − 1 2 ASL\approx log_2(b+1)+\frac{s-1}{2} ASLlog2(b+1)+2s1

查找方法比较

在这里插入图片描述

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值