查找——有序表查找

1、折半查找

折半查找又称二分查找,时间复杂度为O(log_{n}),它的前提t条件是有序顺序存储,对于静态查找表,一次排序后不再变化,这样的算法已经比较好了。但对于需要频繁插入或删除操作的数据来说,维护有序的排序会带来不小的工作量,不建议使用。

2、插值查找

插值查找是另一种有序表查找算法,其核心就在于插值公式\frac{key-a[low]}{a[high]-a[low]},时间复杂度也是O(log_{n}),但对于表长较大且关键字分布均匀的查找表来说,插值查找平均性能比折半查找要好得多。

3、斐波那契查找

斐波那契查找原理是采用黄金分割点作为拆分点的,因为Fibonacci数列F[k]=F[k-1]+F[k-2],所以可以将长度为F[k]的有序顺序表中数据分割成F[k-1]和F[k-2],分割点就是\frac{F[k-1]}{F[k]}\approx 0.618,斐波那契数列随着数列增长越接近0.618。

4、三种有序表查找算法比较

三种有序表查找本质上是分隔点的选择不同,折半查找分隔点是\frac{1}{2},插值查找分隔点是插值点\frac{key-a[low]}{a[high]-a[low]},斐波那契查找分隔点是黄金分割点0.618。各有优劣,实际开发时根据数据的特点综合考虑作出选择。

折半查找进行加法和除法运算(mid=(low+high)/2),插值查找进行复杂的四则运算(mid=low+(high-low)*(key-a[low])/(a[high]-a[low])),而斐波那契查找只有简单的加减法运算(mid=low+F[k-1]-1),在海量数据查找过程中,这种微小的差别可能会影响最终的查找效率。

#include<iostream>
#include<algorithm>
using namespace std;
#define Max 100
//折半查找
int BinarySearch(int *a,int n,int key)
{
	int low=0,high=n-1,mid;
    while(low<=high)
	{
		mid=(low+high)/2;
		if(key<a[mid])
			high=mid-1;
		else if(key>a[mid])
			low=mid+1;
		else
			return mid;
	}
	return 0;
}

//插值查找
int InterpolationSearch(int *a,int n,int key)
{
	int low=0,high=n-1,mid;
	while(low<=high)
	{
		mid=low+(key-a[low])/(a[high]-a[low])*(high-low);
		if(key<a[mid])
			high=mid-1;
		else if(key>a[mid])
			low=mid+1;
		else
			return mid;
	}
	return 0;
}

//斐波那契查找
int *F;  //存储Fibonacci数
//生成Fibonacci数组
void Fibonacci(int n)
{
	F=(int*)malloc(n*sizeof(int));
    if(n>2)
	{
		F[0]=0;
		F[1]=1;
		int i=2;
		while(i<=n)
		{
			F[i]=F[i-1]+F[i-2];
			i++;
		}
	}
}
int FibonacciSearch(int *a,int n,int key)
{
	int low=0,mid,high=n-1,i,k=0;
	//找到n位于斐波那契数列的位置且F[k-1]<=n<F[k]
	while(F[k]<=n)
		k++;
	//将不满的数值补全,也就是数组a下标从n到F[k]-1填充a[n-1]
	for(i=n;i<F[k];i++)
		a[i]=a[n-1];
	//斐波那契查找是以黄金分割点作为分割,F[k]=F[k-1]+F[k-2]也就是对F[k]分割成0到F[k-1]-1共F[k-1]个数字和F[k-1]到F[k]-1共F[k-2]个数字两段
	//如果key<mid则对0到F[k-1]-1段查找,也就是将这一段F[k-1]=F[k-2]+F[k-3]分成了0到F[k-2]-1和F[k-2]到F[k-1]-1,所以k=k-1
    //如果key>mid则对F[k-1]到F[k]-1段查找,也就是将这一段F[k-2]=F[k-3]+F[k-4]分成了0到F[k-2]-1和F[k-2]到F[k-1]-1,所以k=k-2
	while(low<=high)
	{
		mid=low+F[k-1]-1;
		if(key<a[mid])
		{
			high=mid-1;
			k=k-1;
		}
		else if(key>a[mid])
		{
			low=mid+1;
			k=k-2;
		}
		else
		{
			//如果mid小于n,则直接返回mid
			if(mid<=n-1)
				return mid;
			//如果mid大于n,则直接返回n-1说明找到的位于填充的位置
			else
				return n-1;
		}
	}
	return 0;	
}
int main()
{
	int a[Max]={2,5,6,8,3,1,17,39,70,90};
	int n=10,key=1;
	sort(a,a+n);
	Fibonacci(n);
	cout<<FibonacciSearch(a,n,key)<<endl;
    cout<<BinarySearch(a,n,key)<<endl;
    cout<<InterpolationSearch(a,n,key)<<endl;
	return 0;
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值