数据结构之查找(三)——有序表查找

折半查找

折半查找(Binary Search)技术,又称为二分查找。它的前提是线性表中的记录必须是关键码有序(通常从小到大有序),线性表必须采用顺序存储。

折半查找的基本思想是:在有序表中,取中间记录作为比较对象,若给定值与中间记录的关键字相等,则查找成功;若给定值小于中间记录的关键字,则在中间记录的左半区继续查找;若给定值大于中间记录的关键字,则在中间记录的右半区继续查找。不断重复上述过程,直到查找成功,或所有查找区域无记录,查找失败为止。


折半查找的时间复杂度为:O(logn)。


折半查找算法

//折半查找,a为数组,n为要查找的数组个数,key为要查找的关键字
int BinarySearch(int *a, int n, int key) {
	//定义最低下标为记录首位
	int low = 1;
	//定义最高下标为记录末位
	int high = n;
	int mid;
	while (low <= high) {
		//折半
		mid = (low + high) / 2;
		//若查找值比中值小
		if (key < a[mid]) {
			//最高下标调整到中位下标小一位
			high = mid - 1;
		}
		//若查找值比中值大
		else if (key > a[mid]) {
			//最低下标调整到中位下标大一位
			low = mid + 1;
		}
		else {
			//若相等则说明mid即为查找到的位置
			return mid;
		}
	}
	return 0;
}


 
差值查找 

插值查找(Interpolation Search)是根据要查找的关键字key与查找表中最大最小记录的关键字比较后的查找方法,其核心就在于插值的计算公式(key-a[low])/(a[high]-a[low])。

插值查找的时间复杂度为:O(logn)。

但对于表长较大,而关键字分布又比较均匀的查找表来说,差值查找算法的平均性能比折半查找要好得多。反之,数组中如果分布类似{0,1,2,2000,2001,.....,9999998,9999999}这种极端不均匀的数据,用插值查找未必是很合适的选择。

差值查找算法

//插值查找,a为数组,n为要查找的数组个数,key为要查找的关键字
int InterpolationSearch(int *a, int n, int key) {
	//定义最低下标为记录首位
	int low = 1;
	//定义最高下标为记录末位
	int high = n;
	int mid;
	while (low <= high) {
		//插值
		mid = low + (high - low)*(key - a[low]) / (a[high] - a[low]);
		//若查找值比中值小
		if (key < a[mid]) {
			//最高下标调整到中位下标小一位
			high = mid - 1;
			cout << 11;
		}
		//若查找值比中值大
		else if (key > a[mid]) {
			//最低下标调整到中位下标大一位
			low = mid + 1;
		}
		else {
			//若相等则说明mid即为查找到的位置
			return mid;
		}
	}
	return 0;
}


斐波那契查找

斐波那契查找(Fibonacci Search),它是利用了黄金分割原理来实现的。


斐波那契查找的时间复杂度为:O(logn)。

就平均性能来说,斐波那契查找要优于折半查找。

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


斐波那契查找

//斐波那契查找查找,a为数组,n为要查找的数组个数,key为要查找的关键字,F是斐波那契数列,F={0,1,1,2,3,4,8,13,21,.....}。
int FibonacciSearch(int *a, int n, int key) {
	//定义最低下标为记录首位
	int low = 1;
	//定义最高下标为记录末位
	int high = n;
	int mid, i, k = 0;
	//计算n位于斐波那契数列的位置
	while (n > F[k] - 1)
		k++;
	for (i = n; i < F[k] - 1; i++)
		a[i] = a[n];
	while (low <= high) {
		//斐波那契 计算当前分割的下标
		mid = low + F[k-1]-1;
		//若查找值比当前分割记录小
		if (key < a[mid]) {
			//最高下标调整到分割下标mid-1处
			high = mid - 1;
			//斐波那契数列下标减一位
			k = k - 1;
		}
		//若查找值比当前分割记录大
		else if (key > a[mid]) {
			//最低下标调整到分割下标mid+1处
			low = mid + 1;
			//斐波那契数列下标减俩位
			k = k - 2;
		}
		else {
			if (mid <= n)
				//若相等则说明mid即为查找到的位置
				return mid;
			else
				//若mid>n说明是补全数值,返回n
				return n;
		}
	}
	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值