查找算法
顺序表查找
就是遍历查找表,一个一个与目标值进行比对
折半查找(二分查找)
适用于:静态查找表,一次排序后就不再变化的表
①首先待查找的表需有序
②其次进行二分查找,(即每次将表中间的那个元素与目标值进行比较)
根据结果选择保留比对区间
时间复杂度\(O(logn)\)
算法主体:
int Binary_Search(int* arr,int n,int key){
int mid;
int low=0;
int high=n-1;/*数组下标重0开始,最后一个元素下标值为n-1*/
while(low<=high){
mid=(low+high)/2;
if(arr[mid]==key)
return mid;/*返回命中元素的下标*/
if(arr[mid]<key)/*中间值比key小,则在右区间[mid+1,high]查找*/
low=mid+1;
else
high=mid-1;/*中间值比key大,则在左区间[low,mid-1]查找*/
}
return -1;/*查找失败*/
}
插值查找
算法原理参考
适用于:表比较长且关键字分布比较均匀的有序表
是对折半查找算法的优化:
\(mid=low+ fac*(high-low)\)
在二分查找中 \(fac=\frac{1}{2}\)
优化为: \(fac=\frac{key-arr[low]}{arr[high]-arr[low]}\)
即:\(mid=low+ \frac{key-arr[low]}{arr[high]-arr[low]}(high-low)\)
二分查找fac是每次取\(\frac{1}{2}\)
而插值查找是根据:\(\frac{key与左边边界的数值的差值}{arr[low]-arr[high]}\)
的比值动态确定区间的,所以若有序表分布不均匀,则fac可能会比\(\frac{1}{2}大\)
时间复杂度:\(O(logn)\)
算法主体:
int Binary_Search(int* arr,int n,int key){
int mid;
int low=0;
int high=n-1;/*数组下标重0开始,最后一个元素下标值为n-1*/
while(low<=high){
mid=low+(high-low)*(key-arr[low])/(arr[high]-arr[low]);
/*与二分查找不同之处*/
if(arr[mid]==key)
return mid;/*返回命中元素的下标*/
if(arr[mid]<key)/*中间值比key小,则在右区间[mid+1,high]查找*/
low=mid+1;
else
high=mid-1;/*中间值比key大,则在左区间[low,mid-1]查找*/
}
return -1;/*查找失败*/
}
斐波那契查找
参考链接
待查找表有序
利用了斐波那契数列数列f,分割查找表
①首先 在斐波那契数列中找到最小的f[n],使得f[n]大于或等于查找表长度的值
②然后将表长度扩充为f[n],添加的元素的值为原表的最后一个元素
③然后查找时将表分成两部分:左边f[n-1]个元素,右边f[n-2]个元素进行查找
(利用:f[n]=f[n-1]+f[n-2]),其中mid=f[n-1]-1 处
代码:
#include<stdio.h>
#define maxsize 100
int f[100] = { 0,1 };/*全局变量:斐波那契数列*/
/*----------------------------------------------算法主体-----------------*/
int Fibonacci_Search(int* arr, int n, int key) {
int mid;
int low = 0;
int high;/*数组下标从0开始*/
int k = 0;
while (n > f[k]) {/*找到k值*/
k++;
}
for (int i = n; i < f[k]; i++) {
arr[i] = arr[n-1];
}
high = f[k] - 1;/*扩充后最后一个元素的下标*/
while (low <= high) {
mid = low + f[k - 1] - 1;
if (arr[mid] == key) {
if (mid <= n - 1)/*原表的下标*/
return mid;
else
return n - 1;/*匹配的是扩充的元素*/
}
if (arr[mid] < key) {
low = mid+1;
k -= 2;/*f[k]=右半部分的长度*/
}
else {
high = mid-1;
k -= 1;/*f[k]=左半部分的长度*/
}
}
return -1;
}
/*--------------------------------------------------------------------*/
int main() {
/*需要有序,否则需要先进行排序处理*/
int arr[maxsize] = {5,11,12,34,45,65,68,77 };
int index;
for (int i = 2; i < 100; i++) {/*初始化斐波那契数列*/
f[i] = f[i - 1] + f[i - 2];
}
index = Fibonacci_Search(arr, 8, 65);
printf("key=65 在表中下标:%d\n", index);
}
若每次都是保留右半部分则其长度始终为f[k]个;
否则:保留部分的元素个数=f[k]-1个;
首次搜索时:(此时的比对区间长度为f[k])
因为 mid位于左半部分F[K-1]-1的位置,【0,f[k-1]-1】共f[k-1]个元素
①当执行 high=mid-1后【0,high】的元素个数就变成f[k-1]-1个了
②执行low=mid+1时,右边的元素个数保持不变
当首次执行①之后:
比对区间的长度就变成了f[k]-1个了(注:k是动态变化的)
每次划分的时候左边满足f[k-1]个元素,右边会少一个。
因为这样,所以之后无论是执行①还是②,元素的个数始终为f[k]-1个

浙公网安备 33010602011771号