二分查找及有重复值的查找

二分查找

1.二分查找

二分法查找,也称为折半法,是一种在有序数组中查找特定元素的搜索算法。他的时间复杂度为O(logN)

2.在一组没有重复值的升序数组中查找所求数
//代码及其运行截图
int Binarysearch(int* str,int strlen, int target){
	int left = 0;
	int right = strlen - 1;
	while (left <= right){//如果只是left<right,则会少一次比较
		int mid = left+((right-left)>>1);//(left+right)/2容易溢出
		if (*(str + mid) < target){//要找的数在中点的右边
			left = mid+1;
		}
		else if (*(str + mid) > target){//要找的数在中点的左边
			right = mid-1;
		}
		else
		{
			return mid;
			break;
		}
	}
	return -1;
}

int main(){
	int str[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 23, 45 };
	int size = sizeof(str) / sizeof(str[0]);
	int x = Binarysearch(str, size, 11);

	cout << x << endl;
}

这段代码,在没有重复值的升序数组中,运行结果会准确输出,如下运行结果:
!

但是,如果升序数组arr[]={1,2,3,4,4,4,5,5,6,7,8}则输出的结果不会准确,此时我们需要的是出现所找的数的第一个下标或者最后一个下标。

3.在一组有重复值的升序数组中查找所求数

首先我们可以想到,通过二分法拿到一个值,然后再通过这个值向左或向右进行遍历查询,但是此时的时间复杂度为O(logN),因此,我们可以继续通过二分查找法,查找最左或者最右目标值。
查找最左目标值:

//在一组有重复值的升序数组里
int search(int* str,int strlen, int target){
	int left = 0;
	int right = strlen - 1;
	while (left <= right){
		int mid = left+((right-left)>>1);
		if (*(str + mid) >= target)  //此时,假设当mid下标所指的值等于我们所查找的值,先不进行返回,此时最高位指向mid且左移一位
			right = mid - 1;
		else
			left = mid + 1;
		if (*(str + right)<target)  //此时进行上一个条件中right下标所存的数据与我们target值的比较,如果此时此时的值是小于target,那么mid下标所存的数据则为所求数的最左值,进行输出,否则继续循环
			return mid;
		else
			continue;
	}
		return -1;
}

此时我们所求的最左值为3
查找最右目标值:

//在一组有重复值的升序数组里
//查找最右目标值与查找最左目标值的思路相似
int search(int* str,int strlen, int target){
	int left = 0;
	int right = strlen - 1;
	while (left <= right){
		int mid = left+((right-left)>>1);
		if (*(str + mid) <= target)  
			left = mid + 1;
		else
			right=mid-1;
		if (*(str + right)>target) 
			return mid;
		else
			continue;
	}
		return -1;
}

最终代码及结果:

#include<iostream>
using namespace std;
//二分查找,有重复值的二分查找


//在一组有重复值的升序数组里
int right_search(int* str, int strlen, int target){
	int left = 0;
	int right = strlen - 1;
	while (left <= right){
		int mid = left + ((right - left) >> 1);
		if (*(str + mid) <= target)
			left = mid + 1;
		else
			right = mid - 1;
		if (*(str + right) == target )
			return right;
		else
			continue;
	}
	if (left > right)
		return -1;
}


//在一组有重复值的升序数组里
int left_search(int* str, int strlen, int target){
	int left = 0;
	int right = strlen - 1;
	while (left <= right){
		int mid = left + ((right - left) >> 1);
		if (*(str + mid) >= target)  //此时,假设当mid下标所指的值等于我们所查找的值,先不进行返回,此时最高位指向mid且左移一位
			right = mid - 1;
		else
			left = mid + 1;
		if (*(str + left) == target)  //此时进行上一个条件中right下标所存的数据与我们target值的比较,如果此时此时的值是小于target,那么mid下标所存的数据则为所求数的最左值,进行输出,否则继续循环
			return left;
		else
			continue;
	}
	if (left > right)
		return -1;
}



int main(){
	int str[] = { 1, 2, 3, 4, 4, 4, 4, 4, 5, 5, 6, 7, 8, 9, 10 };
	int size = sizeof(str) / sizeof(str[0]);
	cout << "找打5的位置:" << endl;
	int right_x5 = right_search(str, size, 5);
	int left_x5 = left_search(str, size, 5);
	if (left_x5 == right_x5)
	cout << "可知所求数在此数组里只有一个,且下标为" << right_x5 << endl;
	else{
		cout << "他的最左下标值为:" << left_x5 << endl;
		cout << "他的最右下标值为:" << right_x5 << endl;
	}
	cout << "找打2的位置:" << endl;
	int right_x2 = right_search(str, size, 2);
	int left_x2 = left_search(str, size, 2);
	if (left_x2 == right_x2)
		cout << "可知所求数在此数组里只有一个,且下标为" << right_x2 << endl;
	else{
		cout << "他的最左下标值为:" << left_x2 << endl;
		cout << "他的最右下标值为:" << right_x2 << endl;
	}
}

运行截图:
在这里插入图片描述

以上都是我个人所思所得,如果有错误,欢迎在评论区指正。

  • 7
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值