如何寫出乙個正確的二分查詢

2021-09-02 18:51:19 字數 3290 閱讀 6772

總結基於分治思想的乙個很簡單的演算法,但若想寫對,卻也不是那麼容易

使用條件

二分查詢也稱折半查詢(binary search),它是一種效率較高的查詢方法。但是,折半查詢要求線性表必須採用順序儲存結構,而且表中元素按關鍵字有序排列

查詢過程

我們l來看下邊**:

/**

* 二分查詢,找到該值在陣列中的下標,否則為-1

*/int

binarysearch

(int

*a,int asize ,

int key)

return-1

;}

(1)處:,如果是"<"的話,low==high事程式就退出了,處於該位置的元素顯然就被遺漏了。

(2)處:這是乙個很著名的bug!

我們知道,數學中數有無窮大,那麼求其平均數,相加除以二顯然不會有任何的問題。但是在計算機中,所有的數都是以二進位制的形式儲存在記憶體中的,記憶體有限,所以儲存的數自然不可能無窮大。

比如int型資料,現在一般是32位,第一位做符號位,所以它的範圍[-231,231-1],如果low+high超過了231-1那麼就溢位了,顯然結果就不對了。而用我們能這種方法,便可以保證不會有溢位的風險。

二分查詢變種主要有以下幾種:

查詢 第乙個/最後乙個 與key相等的元素

查詢最後乙個等於或者小於key的元素

查詢最後乙個小於key的元素

查詢第乙個等於或者大於key的元素

查詢第乙個大於key的元素

首先,對於這些變種的程式,總會有如下共性:

不變性:

1.迴圈永遠是low>high時才跳出

2if(a[mid]>key) high=mid-1;.

3.if(a[mid]所以,對於每個變種,我們需要考慮的情況:

1.a[mid]==key這種情況的處理

2.最後的結果儲存在low中還是high中

查詢第乙個與key相等的元素

因為我們要找的是第乙個(從左至右),所以當遇到 a[mid]==key 的情況時,肯定不能讓 low=mid+1,否則就錯過了第乙個啦,那麼只能讓 high=mid-1 嘍!

當然,我們再正面分析一下:

if

(a[mid]

>=key)

high = mid -1;

//為了破壞if中的條件

上述**迴圈執行到最後,high指標所指向的元素一定是據key最近的小於key的元素;

if

(a[mid]

low=mid+1;

//為了破壞if中的條件

上述**迴圈執行到最後,low指標所指向的元素一定是大於等於key這些元素中的第乙個元素(從左至右)。

非正式的驗證了演算法的正確性,而且知道了最後的結果儲存在low中.

以下是完整**:

int

binarysearch

(int

*a,int asize ,

int key)

if(low < asize && a[low]

==key)

//注意這裡應該防止low溢位

return low;

return-1

;}

查詢最後乙個與key相等的元素

因為要找最後乙個,所以第一次遇到 a[mid]==key 時,應該選擇low=mid+1;

迴圈破壞 a[mid]<=key 後,low所指元素為大於key的第乙個元素;

迴圈破壞 a[mid]>key 後,high為小於等於key的最大序號。所以,最後的結果儲存在high中。

完整**如下:

int

binarysearch

(int

*a,int asize ,

int key)

if(high >=

0&& a[high]

==key)

//注意這裡應該防止high溢位

return high;

return-1

;

查詢最後乙個等於或者小於key的元素

就是查詢最後乙個與key相等的元素中的high,分析同上,**如下:

int

binarysearch

(int

*a,int asize ,

int key)

return high;

查詢最後乙個小於key的元素

就是查詢第乙個與key相等的元素的high,分析同上,**如下:

int

binarysearch

(int

*a,int asize ,

int key)

return high;

}

查詢第乙個等於或者大於key的元素:

此情況其實與上邊的分析差不多,就不多寫廢話啦。**如下:

int

binarysearch

(int

*a,int asize ,

int key)

return low;

}

查詢第乙個大於key的元素

此情況其實與上邊的分析差不多,就不多寫廢話啦。**如下:

int

binarysearch

(int

*a,int asize ,

int key)

return low;

}

step1.對於所有二分,下邊兩個條件都是必須的,所以我們只需分析 a[mid]==key 應該給high還是low。

1if(a[mid]>key) high=mid-1;.

2.if(a[mid]step2.判斷輸出結果,最普通的二分查詢直接return;其他變種可能在low中,也可能在high中,利用上述我所說 迴圈的目的是為了破壞if條件句中的條件,然後該語句的否定,再加上減一這個條件,即可推出low和 high所存序號的意義。

參考:你真的會寫二分查詢嗎

如何寫好乙個二分搜尋

最近寫了乙個二分搜尋,結果不盡人意,總是出錯。所以翻了一些部落格,看到一些關於使用迴圈不變體的方法來寫二分搜尋。如何寫出正確的二分搜尋 我就寫好乙個二分搜尋進行了一下總結 確定你這個二分的目的,以下會舉7個例子說一下常用的求解target 確定條件,就三個,s mid 確定迴圈的條件 while l...

教你如何寫出乙個碎片輪播

對於幾乎每乙個入行前端的小夥伴來說,輪播圖幾乎都是必修課,但是,只是單純的切換過渡可能並不能滿足於你追求酷炫的心hh,那麼這裡就教你利用css3的clip path來模擬碎片並為你的輪播圖新增碎片輪播的效果!對於一張來說,如果在原有的基礎上新增一層蒙版,遮蔽住不想讓使用者見到的檢視,剩下的檢視即可作...

乙個二分查詢程式

原問題來自 http topic.csdn.net u 20090826 18 c08b69e8 ce22 4427 8687 ffb53e380437.html 問題如下 有一連串字母,由且必由若干個 a,b,c,d,e 組成,順序是 若干個 a,若干個 b,若干個 c,若干個 d,若干個 e 即...