查找算法
本文主要总结程序设计中常用的查找算法。
常见的查找算法主要有顺序查找、二分查找、哈希表查找、二叉排序树查找以及分块查找。
1.顺序查找
顺序查找是按照序列原有顺序对数组进行遍历比较查询的基本查找算法。
- 1.1 条件
无序或有序队列。 - 1.2 原理
对于任意一个序列以及一个给定的元素,将给定元素与序列中元素依次比较,直到找出与给定关键字相同的元素,或者将序列中的元素与其都比较完为止。 - 1.3 时间复杂度:O(n)
2.二分查找
二分查找又称折半查找,是一种效率较高的查找方式。
- 2.1 条件:有序队列。
- 2.2 特点
优点是比较次数少,查找速度快,平均性能好,占用系统内存较少;缺点是要求待查表为有序表,且插入删除困难。
因此,折半查找方法适用于不经常变动而查找频繁的有序列表。 - 2.3 原理(假设表中元素是按升序排列)
(1)确定该区间的中点位置
(2)将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功;否则确定新的查找区间,继续二分查找。其具体方法为:
利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。
重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。 - 2.4 时间复杂度:O(logn)
- 2.5 二分查找代码实现
- 2.5.1 二分查找
/**
* 二分查找,找到该值在数组中的下标,否则为-1
*/
public int binarySearch(int[] array,int key){
int left=0;
int right=array.length-1;
// 这里必须是 <=
while(left<=right){
int mid=(left+right)/2;
if(array[mid]==key)
return mid;
else if(array[mid]>key){
right=mid-1;
}else{
left=mid+1;
}
}
return -1;
}
每次移动left和right指针的时候,需要在mid的基础上+1或者-1, 防止出现死循环, 程序也就能够正确的运行。
注意:代码中的判断条件必须是while (left <= right),否则的话判断条件不完整,比如:array[3] = {1, 3, 5};待查找的键为5,此时在(low < high)条件下就会找不到,因为low和high相等时,指向元素5,但是此时条件不成立,没有进入while()中。
- 2.5.2 二分查找的变种
// 这里必须是 <=
while (left <= right) {
int mid = (left + right) / 2;
if (array[mid] ? key) {
//... right = mid - 1;
}
else {
// ... left = mid + 1;
}
}
return xxx;
对于二分查找的变种,如果条件稍微变换一下,比如:数组之中的数据可能可以重复,要求返回匹配的数据的最小(或最大)的下标;更近一步, 需要找出数组中第一个大于key的元素(也就是最小的大于key的元素的)下标,等等。 这些,虽然只有一点点的变化,实现的时候确实要更加的细心。它们的实现代码都多相似,主要分为以下两个步骤:
(1)首先判断出是返回left,还是返回right
最后跳出while (left <= right)循环条件是right < left,且right = left - 1。最后right和left一定是卡在"边界值"的左右两边,如果是比较值为key,查找小于等于(或者是小于)key的元素,则边界值就是等于key的所有元素的最左边那个,其实应该返回left。
(2)判断出比较符号
也就是这里的 if (array[mid] ? key) 中的判断符号,结合步骤1和给出的条件,如果是查找小于等于key的元素,则知道应该使用判断符号>=,因为是要返回left,所以如果array[mid]等于或者大于key,就应该使用>=,以下是完整代码:
// 查找小于等于key的元素
int mid = (left + right) / 2;
if (array[mid] >= key) {
right = mid - 1;
}
else {
left = mid + 1;
}
3.哈希表查找
哈希查找是通过计算数据元素的存储地址进行查找的一种方法。
- 3.1 条件:先创建哈希表(散列表)
- 3.2 特点
优点是能够在O(1)时间内查找某一元素,是效率最高的查找方式。
缺点需要额外的空间来实现哈希表。 - 3.3 基本原理
根据键值方式(Key Value)进行查找,通过散列函数,定位数据元素。 - 3.4 时间复杂度
几乎是O(1),取决于产生冲突的多少。
4.二叉排序树查找
- 4.1 条件
先创建二叉排序树: 1. 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 2. 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 3. 它的左、右子树也分别为二叉排序树。 - 4.2 基本原理
在二叉查找树b中查找x的过程为: 1. 若b是空树,则搜索失败,否则: 2. 若x等于b的根节点的数据域之值,则查找成功;否则: 3. 若x小于b的根节点的数据域之值,则搜索左子树;否则: 4. 查找右子树。 - 4.3 时间复杂度:O(log2(n))
5.分块查找
- 5.1 思想:顺序查找和二分查找的结合。
- 5.2 原理
将n个数据元素"按块有序"划分为m块(m ≤ n)。 每一块中的结点不必有序,但块与块之间必须"按块有序";即第1块中任一元素的关键字都必须小于第2块中任一元素的关键字; 而第2块中任一元素又都必须小于第3块中的任一元素,……。 然后使用二分查找及顺序查找。 - 5.3 时间复杂度:介于O(n) 和O(logn)之间。
参考:
【1】你真的会写二分查找吗 https://www.cnblogs.com/luoxn28/p/5767571.html
【2】常用查找算法(顺序、折半、二叉树、哈希、分块)介绍 https://blog.youkuaiyun.com/guoweimelon/article/details/50906299