# Algorithms - Binary Search
###### tags: `Algorithms` `javascript` `Computer science` `Binary Search`
### 9 Ace J <font size=1 color='blue'>(台語,發音night ace j ,翻譯:為啥是binary search)</font>
『演算法(*Algorithms*)』本猩至今30年歲月無意識下每天都會接觸到,但並不在意,直至今日本猩終於願意面對這歷史久遠的方法,然而第一印象最深刻的即是『二分搜尋演算法(*Binary Search*)』(後文皆以*Binary Search*表示)他近期出現在我眼中次數大幅提升,我無意間也注意到他了。接下來就一起來學習什麼是 *Binary Search* 吧!
### J係蝦密 <font size=1 color='blue'>(台語,翻譯:binary search 是什麼?)</font>
*Binary Search* 是一種應用在有序條件的序列中找出目標項目的高效演算法。原理即是將有序序列一分為二選擇有可能包含目標項目的那一半,重複一分為二的動作直到剩下一個項目為止。
Demo:
在序列中找出 3
- 有序序列 {1,3,5,7,9}
- 一分為二 {1,3,5,7,9} 中間數為5; 5>3 所以選擇左邊
- (重複動作)一分為二 {1,3} 1<3 所以選擇右邊
- 剩下一位 {3} 3=3
### 咩銃蝦<font size=1 color='blue'>(台語,翻譯:binary search 幹嘛用?)</font>
來了,這裡應該有人會發現說,為什麼要這麼麻煩?不就從頭開始算就好還比較快,高效?!高效在哪裡,聽你在放....喔喔喔太兇是不是重來重來....維~
話說我就是覺得一個一個數蠻簡單的,為何還要搞個什麼演算法然後還那麼麻煩,但事實上歹誌不像憨猩想的那麼簡單,聽我say來,今天序列如果是5個10個數字以內一個個數是蠻快的,程式找更快for迴圈給他用下去連滑鼠點下run的時間都比找到數目標數字的時間還久。
但是,對但是今天如果是數千數萬個項目組成呢?一個一個去數可能也可以找得到but do you want?你說for迴圈用下去啊,好來了聽本猩用效能全開簡直快熱當的腦部運轉解釋給各位大德。
以下解釋
#### *簡易搜尋法*(一個一個找):
for迴圈去尋找的時候我最多必須走$n$個步驟才能知道是否有我要的項目,例如1~9999,我要找9487時,我是不是要走9487次迴圈。
#### 那*Binary Search*呢?
我們要派出『對數(*log*)』運算符號,為什麼是*log*?
##### 這邊來幫大家回味一下*log*:
這邊有一個數$x$是$10$的$y$次方可以表示成 $x=10^y$
那反之$x$在底數10的情況下對數是$y$可以表示成 $log_{10}x=y$
所以用口語描述*binary search*時就是我要將數列一直一分為二直到找出目標或者證明目標不在,所以底數為2然而最大步驟數就是 $log_{2}n$
那套入1~9999要找9487我們要最多要走$log_{2}9999$次以下一一算給你看
<table>
<tr>
<th>步驟</th>
<th>第一組</th>
<th>第二組</th>
</tr>
<tr>
<td>1</td>
<td>1~4999</td>
<td style="background:Green;color:white">5000~9999</td>
</tr>
<tr>
<td>2</td>
<td>5000~7499</td>
<td style="background:Green;color:white">7500~9999</td>
</tr>
<tr>
<td>3</td>
<td>7500~8749</td>
<td style="background:Green;color:white">8750~9999</td>
</tr>
<tr>
<td>4</td>
<td>8750~9374</td>
<td style="background:Green;color:white">9375~9999</td>
</tr>
<tr>
<td>5</td>
<td style="background:Green;color:white">9375~9686</td>
<td>9687~9999</td>
</tr>
<tr>
<td>6</td>
<td style="background:Green;color:white">9375~9530</td>
<td>9531~9686</td>
</tr>
<tr>
<td>7</td>
<td>9375~9452</td>
<td style="background:Green;color:white">9453~9530</td>
</tr>
<tr>
<td>8</td>
<td style="background:Green;color:white">9453~9491</td>
<td>9492~9530</td>
</tr>
<tr>
<td>9</td>
<td>9453~9471</td>
<td style="background:Green;color:white">9472~9491</td>
</tr>
<tr>
<td>10</td>
<td>9472~9481</td>
<td style="background:Green;color:white">9482~9491</td>
</tr>
<tr>
<td>11 <a style="color:blue">find it !</a></td>
<td>9482~9486</td>
<td style="background:Green">
<a style="color:pink">9487</a>
<a style="color:white">~9491</a>
</td>
</tr>
</table>
$log_{2}9999\approx13$ 以上也只用$11$步就找到了是不是長知識了呢!(我是...)
所以呢 **9487步** vs **11步** 這邊就可以體現出*Binary Search*的效能了吧!是吧是吧?!
### 安抓擁<font size=1 color='blue'>(台語,翻譯:binary search 怎麼用?)</font>
本猩說到這邊,是不是應該要去把*Binary Search*實作出來捏?應該要吧?是吧?嘿對!就是接下來就是我們的coding時間!!
等等等等等!!!
先別猴急,這邊還有一些狀況需要解釋,首先感謝你們願意看到這邊,再來就是我相信大家對於*Binary Search*都有一定的基礎概念了,可是要如何將腦中的想法翻譯給電腦執行呢?
人腦很奇妙只需要模糊的指令,就能自行完成中間的串連(這是所謂的腦補嗎?)
但是電腦不是人腦,他只會執行你下的指令,就好比說你下達一道命令給人跟電腦時:
小猩猩:「把拔,過來!」
本猩就會用百米9秒的速度直衝小猩猩面前然後說:「是,什麼事?」
但是如果本猩是個電腦那小猩猩要該要對我下達:
```
定義:把拔=電腦自己
過來方法定義:
跑步方法(true)
尋路方法...
閃避障礙物方法...
辨識小猩猩方法...
...
...
跑步方法(boolean 跑步):
int i =0;
while (跑步) {
把拔身體向前傾斜20度
if(i==0){
把拔左手向前擺動45度
把拔右手向後擺動45度
右腳大腿向上提起90度
}else{
把拔右手向前擺動45度
把拔左手向前擺動45度
左腳大腿向上提起90度
}
}
...方法不一一贅述
```
靠很扯耶...
哈,不過就是這麼有趣,來吧開始囉!
所以這邊就會使用到一個叫做***pseudocode***的小方法。
>***Pseudocode:***
**連接人類語言與程式語言的橋樑**
因為人類語言對於電腦來說是不夠精確的,而程式語言又會需要包含眾多細節像是程式語言本身的要求、處理因為不正確的輸入/使用者操作/系統方面導致錯誤等等的問題。
所以人們發展出混合了人類語言與程式語言稱之為*pseudocode*的東東,利用*pseudocode*描述一個功能的邏輯,方便人類理解並且更容易地轉換成程式語言。
*Binary Search Pseudocode*
我們會**輸入**一個有序序列**Array**以及目標數字**target**,以序列中有多少元素**n**,來設定我們的搜索索引**index**範圍**min**,**max**,然後輸出為序列中的索引值**index**。
1. 令 min=0,max=n-1
<font color="blue" size=1>因為index是由0開始排序所以Array最小值為0最大值為n-1</font>
2. 電腦會需要取得**min**與**max**的平均數(無條件捨去)作為猜測的值所以會有一個整數 **guess**
3. 若 **array**[**guess**] 等於 **target**,則停止,找到目標回傳 **guess**
4. 若 **array**[**guess**]小於 **target**,則令**min** = **guess** + 1
5. 除此之外,若**array**[**guess**]>**target**,令 **max** = **guess** - 1.
6. 回到步驟2直到找到**target**或者確認序列裡沒有**target**為止
#### 實際操作
javascript
```
var binarySearchTarget = function(array,target){
var min = 0;
var max = array.length - 1;
var guess;
var times=0;//循環次數
//當min>max的時候可以判斷為此序列沒有target
while(max>=min){
times++;//循環一次+1
guess = Math.floor((max+min)/2);//max+min 平均並無條件捨去
console.log("guess index = " + guess +",min~max = "+array[min]+"~"+array[max]);
if(array[guess] === target){
//當猜的數字與target相同時回傳guess(index)
console.log("times = "+times);
return guess;
}else if(array[guess] < target){
//當猜的數字小於target時min = guess+1
min = guess + 1;
}else {
//當猜的數字大於target時max = guess-1
max = guess - 1;
}
}
return -1;
};
```
驗證
```
input 1~9999 Array, target 9487
guess index = 4999,min~max = 1~9999
guess index = 7499,min~max = 5001~9999
guess index = 8749,min~max = 7501~9999
guess index = 9374,min~max = 8751~9999
guess index = 9686,min~max = 9376~9999
guess index = 9530,min~max = 9376~9686
guess index = 9452,min~max = 9376~9530
guess index = 9491,min~max = 9454~9530
guess index = 9471,min~max = 9454~9491
guess index = 9481,min~max = 9473~9491
guess index = 9486,min~max = 9483~9491
times = 11
//11步完成
output 9486
```
### 終貢己故<font size=1 color='blue'>(台語,翻譯:結論)</font>
以上就是本猩對*Binary Srearch*初略的見解下次分享 ***Tree*** 要怎麼種囉!
感謝諸位大德耐心看完,若有什麼建議或糾正都可以提出唷!
甘溫~
###### 資料來源
```
https://www.khanacademy.org/
https://stackoverflow.com/
https://developer.mozilla.org/
```