顺序查找、折半查找和分块查找

顺序查找和折半查找

顺序查找

一、算法思想

顺序查找,又叫“线性查找”,通常用于线性表
算法思想:从头到尾挨个找(或者反过来也OK)

二、算法实现

结构体定义

typedef struct{
	ElemType *elem;
	int TableLen;
}SSTable;

1.不使用哨兵

int seqSearch(SSTable ST, ElemType key){
	for(int i = 0; i < ST.TableLen; i++){
		if(ST.elem[i] == key){
			return i;
		}
	}
	return -1;
}

2.使用哨兵(0号位置存哨兵)

int seqSearchSentinel(SSTable ST, ElemType key){
	elem[0] = key;
	for(int i = ST.TableLen; i >= 0; i--){
		if(elem[i] == key){
			return i;
		}	
	}
}

优点:无需判断是否越界,效率更高

3.查找效率分析
ASL成功=(1+2+3+…+n)/n=(n+1)/2
ASL失败=n+1

三、算法优化

1.顺序查找的优化(有序表)
用查找判定树分析ASL
共有n+1种查找失败的情况(n+1个失败结点,n个成功结点)
ASL失败=(1+2+3+…+n+n)/(n+1)=n/2+n/(n+1)
一个成功结点的查找长度=自身所在层数
一个失败结点的查找长度=其父节点所在层数
默认情况下,各种失败情况或成功情况都等概率发生
在这里插入图片描述

2.顺序查找的优化(被查概率不相等)
被查概率大的放在靠前位置

折半查找

一、算法思想

1.概念
折半查找,又称“二分查找”,仅适用于有序顺序表(顺序表拥有随机访问的特性,链表没有)。

2.查找过程:
初始:
low =0
high = TableLen - 1
mid = [(low + high) / 2]这里是向下取整

如果要查找的元素大于mid:
low = mid + 1
如果要查找的元素小于mid:
high = mid - 1
如果要查找的元素等于mid:
直接返回mid

如果low == high == 要查找的元素:
查找成功
如果low在high的右边:
查找失败

二、算法实现

1.定义

typedef struct{ //查找表的数据结构(顺序表)
	ElemType *elem; //动态数组基址
	int TableLen; //表的长度
}SSTable;

2.折半查找

基于升序

binarySearch1

基于降序

binarySearch2

三、查找判定树

  1. 如果当前low和high之间有奇数个元素,则mid分隔后,左右两部分元素个数相等
  2. 如果当前low和high之间有偶数个元素,则mid分隔后,左半部分比右半部分少一个元素
  3. 折半查找的判定树中,若mid = [(low + high) / 2]向下取整,则对于任何一个结点,必有
    右子树结点数 - 左子树结点数 = 0或1
  4. 折半查找的判定树一定是平衡二叉树
  5. 折半查找的判定树中,只有最下面一层是不满的
  6. 因此,元素个数为n时树高h=[log2(n+1)]向上取整(计算方法同“完全二叉树”)
  7. 判定树结点关键字:左<中<右,满足二叉排序树的定义
  8. 对于有n个成功结点的折半查找判定树,失败结点:n+1个(等于成功结点的空链域数量)
  9. 树高h=[log2(n+1)]向上取整(该树高不包含失败结点)
  10. 树高h+1=[log2(n+1)]向上取整(该树高包含失败结点)
  11. 查找成功的ASL<=h
  12. 查找失败的ASL<=h
  13. 折半查找的时间复杂度 = O(log2n)

四、折半查找效率

在这里插入图片描述

在这里插入图片描述
ASL成功=(1 * 1 + 2 * 2 + 3 * 4 + 4 * 4) / 11 = 3
ASL失败=(3 * 4 + 4 * 8) / 12 = 11/3

五、拓展思考

1.折半查找的速度一定比顺序查找更快吗?
不一定,比如要查的元素就是第一个元素
2.如果mid=[(low+high)/2]向上取整,判定树时什么样子?

  • 如果当前low和high之间有奇数个元素,则mid分隔后,左右两部分元素个数相等
  • 如果当前low和high之间有偶数个元素,则mid分隔后,左半部分比右半部分多一个元素
  • 折半查找的判定树中,若mid = [(low + high) / 2]向上取整,则对于任何一个结点,必有
    左子树结点数 - 右子树结点数 = 0或1

分块查找

一、算法思想

在这里插入图片描述
特点:块内无序、块间有序

定义

//索引表
typedef struct{
	ElemType maxValue;
	int low, high;
}Index;

//顺序表存储实际元素
ElemType List[100];

分块查找,又称索引顺序查找,算法过程如下:
1.在索引表中确定待查记录所属的分块(可顺序可折半
2.在块内顺序查找

用折半查找查索引
若索引表中不包含目标关键字,则折半查找索引表最终停在low>high要在low所指分块中查找
原因:最终low左边一定小于目标关键字,high右边一定大于目标关键字。而分块存储的索引表中保存的是各个分块的最大关键字。
low超出索引表范围,查找失败。

二、查找效率分析(ASL)

在这里插入图片描述

共有14个元素,各自被查概率为1/14
若索引表采用顺序查找,则7:2次、10:3次、13:3次
若索引表采用折半查找,则30:4次、27:2次?
ASL=∑PiCi
查找失败的情况更复杂…一般不考

假设,长度为n的查找表被均匀地分为b块,每块s个元素
(n=sb --> b=n/s)
设索引查找和块内查找的平均查找长度分别Li、Ls,则分块查找的平均查找长度为ASL=Li+Ls

1.用顺序查找查索引表,(这个是重点)
则Li=(1+2+…+b)/b=(b+1)/2,Ls=(1+2+…+s)/s=(s+1)/2,
则ASL=(b+1)/2+(s+1)/2=(s^2+2s+n)/2s,
s=(根号n)时,ASL最小= (根号n) + 1
若n=10000,则ASLmin=101

2.用折半查找查索引表
则Li=[log2(b+1)]向上取整,Ls=(1+2+…+s)/s=(s+1)/2
则ASL=[log2(b+1)]向上取整+(s+1)/2

三、拓展思考

若查找表是“动态查找表”,有木有更好的实现方式?
链式存储
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

和安韩Pro

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值