基础数据结构-二分变形C语言实现

基础二分

下面是一个最基础的二分搜索代码,从一个数组(数据从小到大排)中找出某元素。

#include <stdio.h>

// 函数声明
int binarySearch(int arr[], int left, int right, int x);

int main() {
    // 测试数据
    int arr[] = {2, 3, 4, 10, 40};
    int n = sizeof(arr) / sizeof(arr[0]);
    int x = 10; // 要查找的元素

    // 调用二分搜索函数
    int result = binarySearch(arr, 0, n - 1, x);

    // 输出结果
    if(result == -1)
        printf("元素 %d 不在数组中\n", x);
    else
        printf("元素 %d 的索引是 %d\n", x, result);

    return 0;
}

// 二分搜索函数定义
int binarySearch(int arr[], int left, int right, int x) {
    while (left <= right) {
        int mid = (left+right) / 2; // 计算中间索引

        // 检查 x 是否在中间
        if (arr[m] == x)
            return m;

        // 如果 x 大于中间元素,则忽略左侧
        if (arr[m] < x)
            left = m + 1;
        else
            right = m - 1;
    }

    // 元素不存在
    return -1;
}

二分变式一

我们希望找出不小于某数x的最小数(不大于某数x的最大数也是同理),数据从小到大排。

这时要注意,在分析的时候我们可以分成三类情况来讨论:

1、找到了x,这时我们应该继续往右走,右边才是我们要找的

2、比x大,这时左边可能要往左走,但是可能此时这个就是我们要找的

3、比x小,继续往右走

根据这三种情况我们修改代码:

#include<stdio.h>

int min_ge(int *A, int n, int x){
	int left =  0, right = n, mid;
	while (left<right){
		mid = (left + right)/2;
		if (A[mid]>x)right = mid;
		else left = mid + 1;
	}
	return left;
}

int main(){
	int A[] = {8,10,33,49,55,63,63,70,85,85};
	int x;
	printf("请输入要查找的数下限:");
	scanf("%d",&x);
	int p = min_ge(A,10,x);
	if (p<10) printf("第一个数A[%d] = %d\n",p,A[p]);
	else printf("不存在这样的数");
	
	return 0;
	
}

还有两个改动的点:

1、循环条件变为left<right,无需取等,取等的位置已经计算过了

2、返回值为left或者right都行,因为此时两者相等

二分变式二

有一组木棍,我们希望切成K根,每根长度一样,我需要找到最长能切的长度。

这里变式在于寻找的是一个长度,而不是数组里的一个值。

要注意:

1、确定搜索空间,是从1到次长+1

2、编写check函数确认是否满足题目条件。

/*
计算最长木棍的切割方案
*/

#include<stdio.h>

int check(int *A, int n, int K, int mid) {
    int sum = 0;
    for (int i = 0; i < n; i++) {  // 数组下标从0开始
        sum += A[i] / mid;
        if (sum >= K) return 1;
    }
    return 0;  // 这里不需要else,直接返回0
}

int long_stick_cut(int *A, int n, int K){
    int left = 1, right = A[n - 1]+1, mid;
    while (left < right) {  
        mid = (left + right) / 2;
        if (check(A, n, K, mid)) {
            left = mid + 1;  
        } else {
            right = mid;  
        }
    }
    return left-1; 
}

int main(){
    int A[10] = {8, 10, 33, 49, 55, 63, 63, 70, 85, 85};
    printf("L = %d\n", long_stick_cut(A, 10, 32));  
    return 0;
}

思考问题

(某大厂/考研面试题)二分为什么要(left+right)/2呢?我不能随机在[left,right]之间取一个值吗?

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值