查找算法

顺序表查找

就是遍历查找表,一个一个与目标值进行比对

折半查找(二分查找)

适用于:静态查找表,一次排序后就不再变化的表
①首先待查找的表需有序
②其次进行二分查找,(即每次将表中间的那个元素与目标值进行比较)
根据结果选择保留比对区间

时间复杂度\(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个
posted @ 2021-08-24 17:28  ly探长  阅读(80)  评论(0)    收藏  举报