數據結構與算法--二分搜索(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 ~ 231,如果minIndex+maxIndex恰好超過了232,就會導致上溢出,此時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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章