# 二元搜尋法 參考網站 https://ithelp.ithome.com.tw/articles/10213268 https://medium.com/appworks-school/binary-search-%E9%82%A3%E4%BA%9B%E8%97%8F%E5%9C%A8%E7%B4%B0%E7%AF%80%E8%A3%A1%E7%9A%84%E9%AD%94%E9%AC%BC-%E4%B8%80-%E5%9F%BA%E7%A4%8E%E4%BB%8B%E7%B4%B9-dd2cd804aee1 --- > 二元搜尋法前有個前提,來先排序, > 如果還沒排序可用.sort() 來排序 ```python !/usr/bin/env python3 # -*- coding: utf-8 -*- def binary_search(data, key): low = 0 high = len(data)-1 while low <= high: mid = int((low + high) / 2) if key == data[mid]: return mid elif key > data[mid]: low = mid + 1 else: high = mid - 1 return -1 data = [1, 9, 2, 7, 4, 10, 3, 8, 5, 6] key = 7 data.sort() print(data) ret = binary_search(data, key) if ret == -1: print('找不到') else: print('找到索引值' + str(ret)) ``` ## 觀念 a. [3, 5]: 閉區間,代表 3, 4, 5 (包含 3、5) b. (4, 9): 開區間,代表 5, 6, 7, 8 (不包含 4、9) c. [1, 6): 左閉右開區間,代表 1, 2, 3, 4, 5 (包含 1、卻不包含 6 ) > > ## **問題** 1. 最上面的 while 迴圈裡面,為什麼我們要寫 left <= right,不能只寫 left < right 嗎?或說,當 left == right 時,需要繼續嗎? 2. right 的起始點為什麼是 array 的長度 -1,不能直接是 array 長度嗎? 3. 中間判斷邊界移動時,為什麼是 right = mid-1 跟 left = mid+1,如果不要 -1 跟 +1 或只有其中一邊+-1,會出錯嗎? ## **解答** 現在我們可以來回答上面三個問題了,問題的答案其實都是一樣的:因為我們定義的 left 與 right 是**閉區間**,也就是包含 left 端點與 right 端點。 問題 1 的答案:當我們 left == right 的那一刻,例如 left == 3、right == 3 好了,那代表可能答案會在 [3,3] 之間,這是個合理的區間,且區間裡只有 3 一個元素,所以當然要再跑一次,確定他是不是我們要的答案,因此 while 的判斷式會是 <= 而非 <。 問題 3 的答案:為什麼要 +-1,同理,因為我們要的答案是**閉區間**,假如 mid 不是答案(因為我們的if else 判斷式已經有一個是判斷是不是Mid==key 了,所以假設會走到另外兩個分支,則必定mid ≠key ),那 mid 必須被排除在**可能是答案的區間**裡,因此不需要再考慮他,直接用 [left, mid-1] 或 [mid+1, right] 當成新的區間即可。 問題 2 的答案:需要一點細心觀察,假如今天我們把 right 定義成 array 長度,也就是”最大的可能 index” + 1 的位置上,首先當然違反了閉區間的原則,因為”最大的可能 index” + 1 不可能是答案,不然就超出 array 範圍了。實際操作時,假如我們的 target 大於 array 裡面最大元素的值,例如 target = 11,我的左邊界就會不停的往右移動 mid+1, mid+1,…,最終他會跑到 left == right,且兩個都停在最大的 index +1,還記得 left == right 的時候我們要再跑一次,而此時 mid 的計算方式會讓我們得出 mid == left 的結果,最終我們的 nums[mid] 就會訪問一個超出範圍的位置,這顯然是很危險的,有些程式語言直接報錯,有的則會給你任意可能的回答,讓你以為沒問題,其實更加危險。