数据结构与算法--二分搜索(binary search)

前言

之前面试准备秋招,重新翻起了《编程之美》。在第三章节看到了一道关于二分搜索的讨论,觉得有许多细节是自己之前也没怎么特别注意地方,比如二分搜索的初始条件,转化、终止条件之类的。

问题

找出一个有序(字典序)字符串数组 arr 中值等于字符串v的元素的序号,如果有多个元素满足这个条件,则返回其中序号最大的。

分析

如果去掉“返回序号最大的”,则标准的二分解法。但是数据中有重复元素,要求返回序号序号最大的元素序号。

以下是有BUG的解法:


int bisearch(int** arr, int b, int e, int* v)
{
    int minIndex = b, maxIndex = e, midIndex;
    while(minIndex < maxIndex)
    {
        midIndex = (minIndex + maxIndex) / 2;
        if(strcmp(arr[midIndex], v) <=0)
            midIndex = minIndex;
        else
            midIndex = maxIndex - 1;
    }
    if(!strcmp(arr[maxIndex], v))
        return maxIndex;
    else
        return -1;
}
  • 可能存在上溢出
midIndex = (minIndex + maxIndex) / 2;

咋一眼看去没什么大的问题,但是极端情况下可能导致错误。如果这是个32位的程序,32位有符号整数可以标识的范围-2^31 ~ 2^31,如果minIndex+maxIndex恰好超过了2^32,就会导致上溢出,此时midIndex变成负数。

想象一下,当minIndex=2, maxIndex=3, 而arr[minIndex] <= v时,midInde将始终等于minIndex,进入死循环。

正确解法

int bisearch(int** arr, int b, int e, int* v)
{
    int minIndex = b, maxIndex = e, midIndex;
    while(minIndex < maxIndex - 1)
    {
        midIndex = minIndex + (maxIndex - minIndex) / 2;
        if(strcmp(arr[midIndex], v) <=0)
            midIndex = minIndex;
        else
            midIndex = maxIndex;
    }
    if(!strcmp(arr[maxIndex], v))
        return maxIndex;
    else if(!strcmp(arr[maxIndex], v))
        return minIndex;
else:
        return -1;
}

扩展问题

给定一个有序(不降序)数组arr:

  • 求任意一个使得arr[i]等于v,不存在则返回-1
  • 求最小的i使得arr[i]等于v,不存在则返回-1
  • 求最大的i使得arr[i]等于v,不存在则返回-1
  • 求最大的i使得arr[i]小于v,不存在则返回-1
  • 求最小的i使得arr[i]大于v,不存在则返回-1
原文地址:https://www.cnblogs.com/CocoML/p/12727384.html