資料結構與演算法入門指南 二分

2021-10-10 22:57:11 字數 3332 閱讀 9351

二分指在有序的陣列中快速查詢某個值,這裡不得不提到我們生活中經常遇到的乙個小遊戲:猜數字,給定乙個範圍,讓你猜某個數字,每次猜錯就告訴你是大了還是小了。

按照二分的思想,猜數字時我們會直接猜中間的數字,比如給出範圍1~1000,我們會直接猜500,再看是大了還是小了再折半縮小需要猜的範圍,這樣就可以用最少的次數猜到數字。

例如我們要在1~1000的範圍內猜799,注意:預設下取整

猜(1 + 1000) / 2 = 500:小了

猜(500 + 1000) / 2 = 750:小了

猜(750 + 1000) / 2 = 875:大了

猜(750 + 875) / 2 = 812:大了

猜(750 + 812) / 2 = 781:小了

猜(781 + 812) / 2 = 796:小了

猜(796 + 812) / 2 = 804:大了

猜(796 + 804) / 2 = 800:大了

猜(796 + 800) / 2 = 798:小了

猜(798 + 800) / 2 = 799:完畢

雖然例子比較長,但應該能換來清晰直觀的理解。

可以發現每次都是(左端點 + 右端點) / 2,再看是大了還是小了去限制左端點和右端點,如果是大了就縮小右端點的值,如果是小了就擴大左端點的值。

c++自帶的lower_boundupper_bound這兩個函式,可以幫我們用二分在陣列中快速查詢某個值。

注意:陣列必須是有序的(這兩個函式預設陣列是從小到大排序的),如果要在無序陣列中查詢則需要先排序,可以看看 資料結構與演算法入門指南 - 排序

lower_bound(begin, end, x)返回在(begin, end-1)區間中第乙個大於等於x的值的位址。

upper_bound(begin, end, x)返回在(begin, end-1)區間中第乙個大於x的值的位址。

可以看到lower_boundupper_bound的區別就是乙個可以等於x,可以只能大於x。

如果x不在陣列中,這兩個函式會返回什麼呢?

那麼我們來看看實際用法吧

int a[10]

=;int index =

lower_bound

(a, a +10,

9)- a;

//獲取符合值的下標 用返回元素的位址減去首位址就是下標了

int value = a[index]

;//獲取值 也可以一步到位 value = *lower_bound(a, a + 10, 9)

如何判斷x是否在陣列內呢?

int a[10]

=;int index =

lower_bound

(a, a +10,

11)- a;

//獲取符合值的下標

//判斷下標是否出界和值是否相同即可

if(index <

10&& a[index]

==11

)puts

("11在a中");

else

puts

("11不在a中"

);

如果陣列是從大到小排序的呢?就不能用lower_boundupper_bound了嘛?當然不是,這兩個方法還有第四個引數,傳入方法或匿名函式,可以自定義排序。

int a[10]

=;int value =

*lower_bound

(a, a +10,

66, greater<

int>()

);//value = 66

有些可以用二分法來快速查詢值的情況,但無法直接用lower_boundupper_bound怎麼辦呢?就例如結構體陣列中要查詢某個元素的屬性符合該值,那麼我們就只能手寫二分了。

由於邊界問題會導致死迴圈,所以某些情況下需要+1-1

bool

check

(int x)

// 檢查x是否滿足某種性質

// 區間[l, r]被劃分成[l, mid]和[mid + 1, r]時使用

intbsearch

(int l,

int r)

return l;

}// 區間[l, r]被劃分成[l, mid - 1]和[mid, r]時使用

intbsearch

(int l,

int r)

return l;

}

看個小栗子?,其實就是把lower_bound實現了,動動手,看能不能寫出upper_bound的效果(查詢大於x的第乙個值)?

int a[10]

=;int x =35;

// 要查詢的值

int l =

0, r =9;

while

(l < r)

cout << l <<

' '<< a[l]

;// 6 35

這裡需要提一下的就是,判斷兩個浮點數是否相等的方法一般是不會用==來判斷的,會有誤差,那麼我們只需要判斷兩個浮點數差的絕對值非常小就行了。1e-6 = 0.000001

bool

check

(double x)

// 檢查x是否滿足某種性質

double

bsearch

(double l,

double r)

return l;

}

再來看個栗子?,數的三次方根。

double x =99;

//要求99的三次方根

double l =

-10e5

, r =

10e5

;//可以取大一點範圍,二分的效率很高的

while

(r - l >

10e-8

)//如果兩個浮點數不相等

cout << l;

// 4.62606

待增加,還是放上洛谷的官方題單。

【演算法1-6】二分查詢與二分答案 - 題單 - 洛谷 | 電腦科學教育新生態 (luogu.com.cn)

資料結構與演算法 二分查詢

二分查詢的思想是在已經排序 公升序 的陣列中,如果要查詢的數比中位數小,那麼其位置只可能在左半部分,相反只能在右半部分。這樣每次把查詢區間縮小一半,比順序查詢效率快得多。非遞迴寫法 public static int binarysearchinasclooply int nums,int star...

資料結構與演算法,二分查詢

1.時間複雜度 每次能去掉一半即 logn 2.實現方式 while迴圈 與 遞迴 我更推薦 while 迴圈,因為遞迴有個潛在的問題就是 stack over flow 堆疊溢位 而且在實際工程中是盡量避免遞迴的。雖然遞迴寫起來方便,也不容易出錯。3.實現關鍵點 我總結了下,一共有以下四點 sta...

資料結構與演算法 二分查詢

基礎概念 二分查詢又稱折半查詢,它是一種效率較高的查詢方法。二分查詢要求 線性表是有序表,即表中結點按關鍵字有序,並且要用陣列作為表的儲存結構。不妨設有序表是遞增有序的。通俗理解 每次首先找到陣列的中間位置 middle 然後把待查詢數 target 與middle進行比較。如果查詢數target ...