数据结构--二分查找

如何在大量排序好的数据中找到想要的数据?
二分查找:先选取中间的数据,如果要查找的数据就是中间的数据则直接返回,如果比中间的数据大就在右边的数据区间寻找,如果比中间的数据小就在左边的数据区间查找,如此不断递归查找,直到找到目标数据。

无重复数据的二分查找

#include<iostream>
using namespace std;

// 如何在大量排序好的数据中找到想要的数据?
// 二分查找:先选取中间的数据,如果要查找的数据就是中间的数据则直接返回,
// 如果比中间的数据大就在右边的数据区间寻找,
// 如果比中间的数据小就在左边的数据区间查找,
// 如此不断递归查找,直到找到目标数据


int besearchInternally(int* A, int low, int high, int val)
{
	// int mid = (low + high) / 2;
	// 因为当low和high过大时两者之和就有可能溢出,所以可以改进为
	// int mid = low + (high - low) / 2;
	// 如果要将性能优化到极致(因为计算机处理位运算比处理除法要快的多),可以将除以2转化成位运算  
	// >>n表示将二进制数整体向右移n位,当n=1时就相当于除以二
	if (high < low)
		return -1;
	int mid = low + ((high - low) >> 1);
	if (val == A[mid])
		return mid;
	else if (val < A[mid])
		return besearchInternally(A, low, mid - 1, val);
	else
		return besearchInternally(A, mid + 1, high, val);
}

// A是要查找的有序数据集,n是数据集的大小,val是要查找的目标数据,
// 返回值是目标数据在数组中的位置,若没有则返回-1
int besearch(int* A, int n, int val)
{
	if (val > A[n-1] || val < A[0])
		return -1;
	return besearchInternally(A, 0, n - 1, val);
}


int main()
{
	int size = 14;
	int x[] = { 1,52,100,101,102,103,104,105,109,120,135,200,800,900};
	int val;
	int n;
	while (true)
	{
		cout << "请输入要查找的数据:";
		cin >> val;
		n = besearch(x, size, val);
		if (n == -1)
			cout << val << "数据不存在" << endl;
		else
			cout << val << ":" << besearch(x, size, val) << endl;
	}
}

存在相同数据
二分查找(查找第一个和要查找数据相同的元素的位置)

#include<iostream>
using namespace std;

// 二分查找变形(查找第一个值等于给定值的元素)
// 主要思路:按照之前的查找方法,先查找到某个等于给定值的元素,
// 然后不断往前,直到前一个元素不等于给定值,就返回


int besearchInternally(int* A, int low, int high, int val)
{
	// int mid = (low + high) / 2;
	// 因为当low和high过大时两者之和就有可能溢出,所以可以改进为
	// int mid = low + (high - low) / 2;
	// 如果要将性能优化到极致(因为计算机处理位运算比处理除法要快的多),可以将除以2转化成位运算  
	// >>n表示将二进制数整体向右移n位,当n=1时就相当于除以二
	if (high < low)
		return -1;
	int mid = low + ((high - low) >> 1);
	if (val == A[mid])
	{
		while (mid>0&&A[mid - 1] == val)
		{
			mid--;
		}
		return mid;
	}
	else if (val < A[mid])
		return besearchInternally(A, low, mid - 1, val);
	else
		return besearchInternally(A, mid + 1, high, val);
}

// A是要查找的有序数据集,n是数据集的大小,val是要查找的目标数据,
// 返回值是目标数据在数组中的位置,若没有则返回-1
int besearch(int* A, int n, int val)
{
	if (val > A[n - 1] || val < A[0])
		return -1;
	return besearchInternally(A, 0, n - 1, val);
}


int main()
{
	int size = 17;
	int x[] = { 1,1,52,100,100,101,102,103,104,105,109,120,135,200,800,900,900 };
	int val;
	int n;
	while (true)
	{
		cout << "请输入要查找的数据:";
		cin >> val;
		n = besearch(x, size, val);
		if (n == -1)
			cout << val << "数据不存在" << endl;
		else
			cout << val << ":" << besearch(x, size, val) << endl;
	}
}

二分查找(查找最后一个和目标数据相同的元素)

#include<iostream>
using namespace std;

// 二分查找变形(查找最后一个值等于给定值的元素)
// 主要思路:按照之前的查找方法,先查找到某个等于给定值的元素,
// 然后不断往后,直到后一个元素不等于给定值或已经到达数组的末尾,就返回

// 区别于之前的二分查找,需要多一个size参数,来控制查找的上限
int besearchInternally(int* A, int low, int high, int val,int size)
{
	// int mid = (low + high) / 2;
	// 因为当low和high过大时两者之和就有可能溢出,所以可以改进为
	// int mid = low + (high - low) / 2;
	// 如果要将性能优化到极致(因为计算机处理位运算比处理除法要快的多),可以将除以2转化成位运算  
	// >>n表示将二进制数整体向右移n位,当n=1时就相当于除以二
	if (high < low)
		return -1;
	int mid = low + ((high - low) >> 1);
	if (val == A[mid])
	{
		while (mid < size-1 && A[mid + 1] == val)
		{
			mid++;
		}
		return mid;
	}
	else if (val < A[mid])
		return besearchInternally(A, low, mid - 1, val,size);
	else
		return besearchInternally(A, mid + 1, high, val,size);
}

// A是要查找的有序数据集,n是数据集的大小,val是要查找的目标数据,
// 返回值是目标数据在数组中的位置,若没有则返回-1
int besearch(int* A, int n, int val)
{
	if (val > A[n - 1] || val < A[0])
		return -1;
	return besearchInternally(A, 0, n - 1, val,n);
}


int main()
{
	int size = 17;
	int x[] = { 1,1,52,100,100,101,102,103,104,105,109,120,135,200,800,900,900 };
	int val;
	int n;
	while (true)
	{
		cout << "请输入要查找的数据:";
		cin >> val;
		n = besearch(x, size, val);
		if (n == -1)
			cout << val << "数据不存在" << endl;
		else
			cout << val << ":" << besearch(x, size, val) << endl;
	}
}

二分查找(查找第一个大于等于给定值的元素)

#include<iostream>
using namespace std;

// 二分查找变形(查找第一个大于等于给定值的元素)
// 主要思路:按照之前的查找方法,如果能查找到就直接返回,
// 如果没有这个数据,当high>low时,也就是查找结束时,返回low
// (此时low就是第一个大于给定值元素的下标)

int besearchInternally(int* A, int low, int high, int val)
{
	// 当hign<low时,表示数组中没有这个数据,这个时候low就是第一个大于给定值的元素
	if (high < low)
	{
		return low;
	}
	// int mid = (low + high) / 2;
	// 因为当low和high过大时两者之和就有可能溢出,所以可以改进为
	// int mid = low + (high - low) / 2;
	// 如果要将性能优化到极致(因为计算机处理位运算比处理除法要快的多),可以将除以2转化成位运算  
	// >>n表示将二进制数整体向右移n位,当n=1时就相当于除以二
	int mid = low + ((high - low) >> 1);
	if (val == A[mid])
		return mid;
	else if (val < A[mid])
		return besearchInternally(A, low, mid - 1, val);
	else
		return besearchInternally(A, mid + 1, high, val);
}

// A是要查找的有序数据集,n是数据集的大小,val是要查找的目标数据,
// 返回值是目标数据在数组中的位置,若没有则返回-1
int besearch(int* A, int n, int val)
{
	// 如果要查找的数据已经比数组中最大的数都大了就直接返回-1
	if ( val > A[n-1])
		return -1;
	return besearchInternally(A, 0, n - 1, val);
}


int main()
{
	int size = 4;
	int x[] = { 1,2,3,5 };
	int val;
	int n;
	while (true)
	{
		cout << "请输入要查找的数据:";
		cin >> val;
		n = besearch(x, size, val);
		if (n == -1)
			cout << "大于等于" << val << "的数据不存在" << endl;
		else
			cout << val << ":" << besearch(x, size, val) << endl;
	}
}

二分查找(查找第一个小于等于给定值的元素)

#include<iostream>
using namespace std;

// 二分查找变形(查找第一个小于等于给定值的元素)
// 主要思路:按照之前的查找方法,如果能查找到就直接返回,
// 如果没有这个数据,当high>low时,也就是查找结束时,返回high
// (此时high就是第一个小于给定值元素的下标)

int besearchInternally(int* A, int low, int high, int val)
{
	// 当hign<low时,表示数组中没有这个数据,这个时候low就是第一个大于给定值的元素
	if (high < low)
	{
		return high;
	}
	// int mid = (low + high) / 2;
	// 因为当low和high过大时两者之和就有可能溢出,所以可以改进为
	// int mid = low + (high - low) / 2;
	// 如果要将性能优化到极致(因为计算机处理位运算比处理除法要快的多),可以将除以2转化成位运算  
	// >>n表示将二进制数整体向右移n位,当n=1时就相当于除以二
	int mid = low + ((high - low) >> 1);
	if (val == A[mid])
		return mid;
	else if (val < A[mid])
		return besearchInternally(A, low, mid - 1, val);
	else
		return besearchInternally(A, mid + 1, high, val);
}

// A是要查找的有序数据集,n是数据集的大小,val是要查找的目标数据,
// 返回值是目标数据在数组中的位置,若没有则返回-1
int besearch(int* A, int n, int val)
{
	// 如果要查找的数据已经比数组中最小的数都小了就直接返回-1
	if (val < A[0])
		return -1;
	return besearchInternally(A, 0, n - 1, val);
}


int main()
{
	int size = 4;
	int x[] = { 1,2,3,5 };
	int val;
	int n;
	while (true)
	{
		cout << "请输入要查找的数据:";
		cin >> val;
		n = besearch(x, size, val);
		if (n == -1)
			cout << "小于等于"<<val << "的数据不存在" << endl;
		else
			cout << val << ":" << besearch(x, size, val) << endl;
	}
}

二分查找的思路很好理解,但是代码不是很好写,尤其是后四个变式,主要要关注递归结束的条件,查找范围的选取,不同情况下返回值的选择,还有最开始的条件判断(如果很明显数据不存在就直接返回)。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值