經典的搜尋法。
概念
跟玩終極密碼的方法一樣,假設有 1 到 100 個按照順序排好的數字,在猜數字時,我們通常會這樣做:
- 一開始猜
50
=> 如果數字比 50 大,接著猜51 ~ 100
- 接著猜
75
=> 如果數字比 75 大,接著猜76 ~ 100
- 接著猜
87
=> 如果數字比 87 大,接著猜88 ~ 100
- 以此類推…
每次都把所有可能拆成兩半,就是二分搜尋法的核心理念。但要切記的一點是,這只適用於「已經排列好的數列」。
實作-遞迴法
1 | // 要遞迴的 function |
詳細流程:
1 | 第一輪 |
補充一
這裡要注意一點,(start > end)
不可以是 >=
,要不然會漏掉一個搜尋:
1 | 第一輪 |
補充二
binarySearchRecursively(array, targetElement, 0, array.length-1)
中的 array.length - 1
不可以改寫成 array.length
。
假設要找的數字是 101
,最後就會去找 array[length]
這個數字,但這已經超出 array 的範圍了,所以會得到 undefined
。這顯然不是件很好的事情,如果換個程式語言有可能就會直接噴 error,或是回傳一個奇怪的答案:
1 | 第一輪 |
實作-迴圈迭代法
1 | function binarySearch(array, targetElement) { |
詳細步驟(跟剛剛差不多):
1 | 第一輪 |
補充
這裡一樣要注意 While (start <= end)
不可以寫成是 <
,不然會忽略掉一個搜尋:
(兩者差別在於,遞迴是「=
時不能跳掉」,這裡是「=
要再找一次」)
1 | 第一輪 |
哪個方法比較好?
根據別人的說法是這樣:
在實作程式的時候,應該要避免使用遞迴(Recursive)的結構,因為遞迴需要不斷地重新建構函數的堆疊空間,硬體資源的負擔會比較大,且若是遞迴層數過多還會導致堆疊溢出(Stack Overflow)。所以比較好的做法還是在一個函數內以迴圈迭代的方式來完成。