數據結構:二分查找的C++實現及細節分析

二分查找可能是最早接觸的查找方式,時間複雜度僅爲O(lg2(n))級別,而且易於理解

但是理解了是一回事,動手寫起來又是一回事,絕大部分人會在是否取等以及邊界值+1的問題上栽倒很多次,就像《只狼》拼刀,看通關視頻都很容易,葦名一心也不過爾爾,結果自己打的時候上來就在新手村先死個20次

先附上原碼:

int binary_search(vector<int>& nums, int target)//搜索後返回數據在數組的座標值,如果不存在則返回-1
{
    int right=nums.size()-1;//二分查找的右極限
    int left=0;//二分查找的左極限
    int middle=left+(right-left)/2;//中間數的座標
    int number=nums[middle];//中間的數據
    while(number!=target)
    {
        if(number>target)
        {
            right=middle;
            middle=left+(right-left)/2;
            number=nums[middle];
        }
        else if(number<target)
        {
            left=middle+1;
            middle=left+(right-left)/2;
            number=nums[middle];
        }
        if(right==left&&number!=target)
            return -1;
    }
    return middle;
}

接下來解釋細節部分:

1.取等問題

很多人都在left和right比較大小的地方猶豫很久,這裏我特意繞開了這個判斷,直接在循環中省去了兩者比較的判斷,單獨列出一個if作爲判斷條件:既然left和right已經取等,說明查找也到了最後一步,如果再沒有合適的值,就直接退出即可

2.+1問題

這裏是絕大部分人在第一次嘗試的時候絕對會栽跟頭的地方

由於計算機計算數據的時候採用2進制編碼數據,對於無法整除數據的情況,採用的是“向0取整”,即:結果大於0的小數,僅保留整數部分,結果小於0的小數,採用進一的方式取整

由於數組的下標均爲非負數,所以二分查找的平均數也一定爲正數,因此,每次取整的時候,數據會偏小,也就是left會更新爲一個較小的整數

例如:當面臨要查找的數據恰好處於下標7上,此時left=6,right=7,每次對middle和left進行更新的時候,left都因爲向下取整的問題而無限循環……

這時候,我們需要捨棄:既然之前,middle上的數據已經不是我們需要的了,那就讓left在頂替middle的時候自動+1

但由於right沒有向下取整的問題,所以不需要進行對應的-1操作,如果進行了-1操作,反而會出現新的問題:

例如,我們在數組[5]當中查找數字-2,此時left,middle,right均爲0,在第一輪循環的時候,由於需要對right進行-1,這時就會出現數組下標負溢出的情況(right=-1)

3.細節問題

由於我們需要查找的數組可能會很大,大到下標即將溢出int型的範圍,這時候我們就要小心了:middle在採用(right+left)/2的計算模式下, 可能會溢出

所以我們修改了middle的計算方式,將其改爲一種較爲安全的計算方法,保證計算的過程中,不會出現溢出的可能

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章