终于找了个时间,把三种静态查找算法简单总结了一下,与大家分享讨论。
完整源代码下载地址
顺序查找
简介
顺序查找是在一个已知无(或有序)序队列中找出与给定关键字相同的数的具体位置。原理是让关键字与队列中的数逐个比较,直到找出与给定关键字相同的数为止。
代码实现
public static int orderSearch(int arr[], int target) {
for (int i = 0; i < arr.length; i++)
if (arr[i] == target)
return i;
return -1;
}
性能分析
时间复杂度:O(n)
二分/折半查找
简介
二分查找又称折半查找,优点是比较次数少,查找速度快,平均性能好;其缺点是要求待查表为有序表,且插入删除困难。
因此,折半查找方法适用于不经常变动而查找频繁的有序列表。
两个条件:1)序列有序;2)可以随机访问
查找过程
首先,假设表中元素是按升序排列,将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功;否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。
代码实现
public static int biSearch(int arr[], int target) {
int low = 0, high = arr.length - 1;
int mid;
while (low <= high) {
mid = low + (high - low) / 2; // 避免溢出
if (arr[mid] == target)
return mid;
else if (arr[mid] < target)
low = mid + 1;
else
high = mid - 1;
}
return -1;
}
性能分析
时间复杂度:O(log2(n))
因为二分查找每次排除掉一半的不适合值,所以对于 n 个元素的情况:
一次二分剩下:n/2
两次二分剩下:n/2/2 = n/4
…….
m次二分剩下:n/(2^m)
在最坏情况下是在排除到只剩下最后一个值之后得到结果,即
n/(2^m)=1
所以由上式可得 : 2^m = n
进而可求出时间复杂度为:m = log2(n)
分块/索引查找
简介
分块查找是折半查找和顺序查找的一种改进方法,分块查找由于只要求索引表是有序的,对块内节点没有排序要求 (块内无序,块间有序),因此特别适合于节点动态变化的情况。
折半查找虽然具有很好的性能,但其前提条件时线性表顺序存储而且按照关键码排序,这一前提条件在结点树很大且表元素动态变化时是难以满足的。而顺序查找可以解决表元素动态变化的要求,但查找效率很低。如果既要保持对线性表的查找具有较快的速度,又要能够满足表元素动态变化的要求,则可采用分块查找的方法。
当增加或减少节以及节点的关键码改变时,只需将该节点调整到所在的块即可。在空间复杂性上,分块查找的主要代价是增加了一个辅助数组。
方法描述
分块查找要求把一个大的线性表分解成若干块,每块中的节点可以任意存放,但块与块之间必须排序。假设是按关键码值非递减的,那么这种块与块之间必须满足已排序要求,实际上就是对于任意的i,第i块中的所有节点的关键码值都必须小于第 i+1 块中的所有节点的关键码值。还要建立一个索引表(索引表中为每一块都设置索引项,每一个索引项都包含两个内容)
- 该块的起始地址
- 该块中最大的元素
比如:
显然,索引表是按关键字非递减顺序排列的。
一般先用二分查找索引表,确定需要查找的关键字在哪一块,然后再在相应的块内用顺序查找。
代码实现
public boolean search(int data) {
int i = binarysearch(data); // 先二分查找确定在哪个块
for (int j = 0; j < list[i].size(); j++) { // 然后顺序查找在该块内哪个位置
if (data == (int) list[i].get(j)) {
System.out.println(String.format("查找元素为 %d 第: %d块 第%d个 元素",data, i + 1, j + 1));
return true;
}
}
return false;
}
/**
* 二分查找
*/
private int binarysearch(int value) {
int start = 0;
int end = index.length;
int mid = -1;
while (start <= end) {
mid = start + (end - start) / 2;
if (index[mid] > value) {
end = mid - 1;
} else {
start = mid + 1; // 如果相等,也插入后面
}
}
return start;
}
性能分析
这种带索引表的分块有序表查找的时间性能取决于两步查找时间之和:如前面所述,第一步可以采用简单顺序查找和折半查找之一进行。第二步只能采用简单顺序查找,但由于子表的长度较原表的长度小。因此,其时间性能介于顺序查找和折半查找之间。
假设索引表有 n 个元素,每块含有 s 个元素,平均查找长度为:ASL = (n / s + s) / 2 + 1,时间复杂度为 O(n)~O(log2n)
综合比较
null | 顺序查找 | 二分查找 | 分块查找 |
---|---|---|---|
表的结构 | 有序、无序 | 有序 | 块内无序、块间有序 |
表的存储 | 顺序、链式 | 顺序 | 顺序、链式 |
平均查找长度 | 最大 | 最小 | 中间 |
时间复杂度 | O(n) | O(log2n) | 中间 |
嘿嘿,公众号粉丝越来越多了,大佬,随手点个关注呗,不光有新鲜的 LeetCode 题解(多种思路,包教包会,开拓思维),还有经典的文章及短视频和大家分享,谢谢!一起嘿嘿嘿!三种静态查找算法:顺序、二分/折半、索引/分块查找
------致所有正在努力奋斗的程序猿们!加油!!
有码走遍天下 无码寸步难行
1024 - 梦想,永不止步!
爱编程 不爱Bug
爱加班 不爱黑眼圈
固执 但不偏执
疯狂 但不疯癫
生活里的菜鸟
工作中的大神
身怀宝藏,一心憧憬星辰大海
追求极致,目标始于高山之巅
一群怀揣好奇,梦想改变世界的孩子
一群追日逐浪,正在改变世界的极客
你们用最美的语言,诠释着科技的力量
你们用极速的创新,引领着时代的变迁
——乐于分享,共同进步,欢迎补充
——Treat Warnings As Errors
——Any comments greatly appreciated
——Talking is cheap, show me the code
——简书:https://www.jianshu.com/u/4968682d58d1
——GitHub:https://github.com/selfconzrr