二分查詢演算法基本思想

2022-03-13 17:28:34 字數 3456 閱讀 5719

**

二分查詢演算法基本思想

二分查詢演算法的前置條件是,乙個已經排序好的序列(在本篇文章中為了說明問題的方便,假設這個序列是公升序排列的),這樣在查詢所要查詢的元素時,首先與序列中間的元素進行比較,如果大於這個元素,就在當前序列的後半部分繼續查詢,如果小於這個元素,就在當前序列的前半部分繼續查詢,直到找到相同的元素,或者所查詢的序列範圍為空為止.

用偽**來表示, 二分查詢演算法大致是這個樣子的:

1 left = 0, right = n -1

2while (left <=right)

3 mid = (left + right) / 2

4case

5 x[mid] < t: left = mid + 1

;6 x[mid] = t: p = mid; break

;7 x[mid] > t: right = mid -1;8

9return -1;

view code

第乙個正確的程式

根據前面給出的演算法思想和偽**, 我們給出第乙個正確的程式,但是,它還有一些小的問題,後面會講到

int search(int array, int n, int v)

else if (array[middle] < v)

else

}return -1;

}

下面,講講在編寫二分查詢演算法時可能出現的一些問題.

邊界錯誤造成的問題

二分查詢演算法的邊界,一般來說分兩種情況,一種是左閉右開區間,類似於[left, right),一種是左閉右閉區間,類似於[left, right].需要注意的是, 迴圈體外的初始化條件,與迴圈體內的迭代步驟, 都必須遵守一致的區間規則,也就是說,如果迴圈體初始化時,是以左閉右開區間為邊界的,那麼迴圈體內部的迭代也應該如此.如果兩者不一致,會造成程式的錯誤.比如下面就是錯誤的二分查詢演算法:

這個演算法的錯誤在於, 在迴圈初始化的時候,初始化right=n,也就是採用的是左閉右開區間,而當滿足array[middle] > v的條件是, v如果存在的話應該在[left, middle)區間中,但是這裡卻把right賦值為middle - 1了,這樣,如果恰巧middle-1就是查詢的元素,那麼就會找不到這個元素.

下面給出兩個演算法, 分別是正確的左閉右閉和左閉右開區間演算法,可以與上面的進行比較:

(下面這兩個演算法是正確的)

死迴圈上面的情況還只是把邊界的其中乙個寫錯, 也就是右邊的邊界值寫錯, 如果兩者同時都寫錯的話,可能會造成死迴圈,比如下面的這個程式:

1

int search_bad2(int array, int n, intv)2

14else

if (array[middle]

1518

else

1922}23

24return -1

;25 }

view code

這個程式採用的是左閉右閉的區間.但是,當array[middle] > v的時候,那麼下一次查詢的區間應該為[middle + 1, right], 而這裡變成了[middle, right];當array[middle] < v的時候,那麼下一次查詢的區間應該為[left, middle - 1], 而這裡變成了[left, middle].兩個邊界的選擇都出現了問題, 因此,有可能出現某次查詢時始終在這兩個範圍中輪換,造成了程式的死迴圈.

溢位前面解決了邊界選擇時可能出現的問題, 下面來解決另乙個問題,其實這個問題嚴格的說不屬於演算法問題,不過我注意到很多地方都沒有提到,我覺得還是提一下比較好.

在迴圈體內,計算中間位置的時候,使用的是這個表示式:

middle = (left + right) / 2;
假如,left與right之和超過了所在型別的表示範圍的話,那麼middle就不會得到正確的值.

所以,更穩妥的做法應該是這樣的:

middle = left + (right - left) / 2;
更完善的演算法

前面我們說了,給出的第乙個演算法是乙個"正確"的程式, 但是還有一些小的問題.

首先, 如果序列中有多個相同的元素時,查詢的時候不見得每次都會返回第乙個元素的位置, 比如考慮一種極端情況:序列中都只有乙個相同的元素,那麼去查詢這個元素時,顯然返回的是中間元素的位置.

其次, 前面給出的演算法中,每次迴圈體中都有三次情況,兩次比較,有沒有辦法減少比較的數量進一步的優化程式?

《程式設計珠璣》中給出了解決這兩個問題的演算法,結合前面提到溢位問題我對middle的計算也做了修改:

1

int search4(int array, int n, intv)2

15else

1619}20

21if (right >= n || array[right] !=v)

2225

26return

right;

27 }

這個演算法是所有這裡給出的演算法中最完善的乙個,正確,精確且效率高.

但是這個演算法的還是不能很好的理解

可以用下面的演算法,可以找出滿足條件的數

1

int bi_search(int a,int n,int b)//

2

16else

if(a[mid]>b)

17 high = mid -1

; 18

else

19 low = mid +1

; 20

} 21

22return

last;

2324

} 25

int bi_search1(int a,int n,int b)//

大於b的第乙個數

26

40else

if (a[mid]<=b)

41

44}

4546

return

last;

47}

48int bi_search(int a,int n,int b)//

49 63

else

if(a[mid]>b)

64 high = mid -1;65

else

66 low = mid +1;67

}6869return

last;

7071}72

int bi_search1(int a,int n,int b)//

大於b的第乙個數

7387

else

if (a[mid]<=b)

8891}92

93return

last;

94 }view code

view code

二分搜尋法基本思想及應用

利用二分法查詢有序陣列 基本思想 left為陣列最左邊,也就是最小數 right為陣列最又,也就是最大數 mid根據 left right 2取下標中間位置的數 num為要查詢的數 若num mid,則num在陣列右半側,所以我們將mid作為新的left,right不變 若numpublic cla...

二分查詢思想

二分查詢思想應用於對有序的陣列進行查詢操作。時間複雜度 二分查詢也稱為折半查詢,每次都能將查詢區間減半,這種折半特性演算法時間複雜度為o logn mid計算 有兩種計算中值mid的方式 l h可能出現加法溢位,也就是說加法的結果大於整形能夠表示的範圍。但是l和h都為正數,因此h l不會出現加法溢位...

KNN演算法 基本思想

knn k 最近鄰居 演算法 該演算法的基本思路是 在給定新文字後,考慮在訓練文字集中與該新文字距離最近 最相似 的 k 篇文字,根據這 k 篇文字所屬的類別判定新文字所屬的類別,具體的演算法步驟如下 step one 根據特徵項集合重新描述訓練文字向量 step two 在新文字到達後,根據特徵詞...