浅谈c++二分查找算法

前言

二分算法,又称为折半查找算法,是一种在有序数组中查找某一特定元素的搜索算法。它的高效性和简洁性使其在许多领域都有着广泛的应用。

一、基本思路

二分算法的核心思想是通过不断地将搜索区间缩小一半,来逐步逼近目标元素。

假设我们有一个有序的整数数组 arr,要查找一个特定的目标值 target

首先,我们定义两个指针,left 指向数组的起始位置,right 指向数组的末尾位置。

然后,计算中间位置 mid = (left + right) / 2 。

接下来,将中间元素 arr[mid] 与目标值 target 进行比较:

  • 如果 arr[mid] == target,则找到了目标元素,算法结束。

  • 如果 arr[mid] > target,说明目标元素在中间元素的左侧,那么将 right 更新为 mid - 1 ,继续在左半部分进行查找。

  • 如果 arr[mid] < target,说明目标元素在中间元素的右侧,那么将 left 更新为 mid + 1 ,继续在右半部分进行查找。

重复以上步骤,直到找到目标元素或者确定目标元素不存在。

二、算法实现

以下是一个使用 C++ 实现二分算法的示例代码:

#include <iostream>
using namespace std;
int binarySearch(int arr[], int left, int right, int target) {
    while (left <= right) {
        int mid = left + (right - left) / 2;

        if (arr[mid] == target) {
            return mid;
        } else if (arr[mid] > target) {
            right = mid - 1;
        } else {
            left = mid + 1;
        }
    }

    return -1;  // 未找到目标元素返回 -1
}

int main() {
    int arr[] = {1, 3, 5, 7, 9, 11, 13};
    int target = 7;

    int result = binarySearch(arr, 0, sizeof(arr) / sizeof(arr[0]) - 1, target);

    if (result!= -1) {
        cout << "目标元素 " << target << " 在数组中的索引为: " << result << endl;
    } else {
        cout << "数组中未找到目标元素 " << target << endl;
    }

    return 0;
}

在上述代码中,binarySearch 函数实现了二分查找的逻辑。在 main 函数中,我们创建了一个有序数组,并指定了要查找的目标值(此处也可以自行输入值),然后调用 binarySearch 函数进行查找,并根据返回结果输出相应的信息。

三、时间和空间复杂度

二分算法的时间复杂度为 O(log n),其中 n 是数组的长度。这是因为每次查找都将搜索区间缩小一半,所以查找的次数与数组长度的对数成正比。

二分算法的空间复杂度为 O(1),因为它只使用了固定的几个变量来存储指针和中间位置等信息,不需要额外的存储空间与数组的长度成正比。

对于无序数组,则需先进行排序(O(n log n)),再进行查找。

四、二分算法的优缺点

优点:

  1. 二分算法的查找效率非常高,时间复杂度为对数级别,在处理大规模数据时具有明显优势。
  2. 算法的逻辑相对简单,易于理解和实现。

缺点:

  1. 二分算法要求待查找的数组必须是有序的。如果数组本身无序,需要先进行排序,这可能会带来额外的时间和空间开销。
  2. 对于频繁插入和删除元素的动态数据集,维护有序性的成本较高,二分算法不太适用。

五、二分算法的应用场景

二分算法常用于以下场景:

  1. 在有序数组中查找特定元素。

  2. 查找满足特定条件的最大值或最小值。

  3. 解决一些可以转化为在有序区间中进行查找的问题。

例如,在一个有序的薪资列表中查找特定薪资的位置,或者在有序的时间序列中查找最早或最晚满足条件的时间点。

六、二分算法的注意事项

  1. 二分算法要求数组必须是有序的,如果数组无序,需要先进行排序。

  2. 在计算中间位置时,要注意防止整数溢出,可以使用 left + (right - left) / 2 的方式。

  3. 当查找的目标值可能不存在时,要正确处理返回值,通常返回 -1 表示未找到。

七、例题讲解

二分查找的例题特别单一,二分更大的用处是二分答案(下一章讲)

题目描述

输入 n 个不超过 109的单调不减的(就是后面的数字不小于前面的数字)非负整数a1​,a2​,…,an​,然后进行 m 次询问。对于每次询问,给出一个整数 q,要求输出这个数字在序列中第一次出现的编号,如果没有找到的话输出 −1 。

输入格式

第一行 2 个整数 n 和 m,表示数字个数和询问次数。

第二行 n 个整数,表示这些待查询的数字。

第三行 m 个整数,表示询问这些数字的编号,从 1 开始编号。

输出格式

输出一行,m 个整数,以空格隔开,表示答案。

输入输出样例

输入 

11 3
1 3 3 3 5 7 9 11 13 15 15
1 3 6

输出 

1 2 -1 

说明/提示

数据保证,1≤n≤10^6,0≤ai​,q≤10^9,1≤m≤10^5

本题输入输出量较大,请使用较快的 IO 方式。

AC代码

#include<bits/stdc++.h>
using namespace std;
int n,m,a[1000010],b,i;
inline int read()
{
    char c = getchar();int x = 0,s = 1;
    while(c < '0' || c > '9') {if(c == '-') s = -1;c = getchar();}//是符号
    while(c >= '0' && c <= '9') {x = x*10 + c -'0';c = getchar();}//是数字
    return x*s;//题里说数据范围很大,所以用快读
}
int main(){
	n=read();
	m=read();
	for(i=1;i<=n;i++)a[i]=read();
	while(m--){
		b=read();
		int l=1,r=n;
		bool falg=true;
		while(l<r){
			int mid=(l+r)>>1;//用位运算来除,提高时间效率
//			if(a[mid]==b){
//				printf("%d ",mid);
//				falg=false;
//				break;
//			}
			if(a[mid]>=b)r=mid;
			else l=mid+1;
		}
		if(a[l]!=b)printf("-1 ");
		else printf("%d ",l);
	}
	return 0;
}

这是我的第七篇文章,如有纰漏也请各位大佬指正

辛苦创作不易,还望看官点赞收藏打赏,后续还会更新新的内容。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值