二分法是思想精髓就是如果左下標和右下標得到的中間下標所在的值等於所要尋找的值,演算法結束;如果中間的值小於目標值,則說明目標值可能在中間值和右下標所在的區間內,就將中間下標當成左下標,繼續搜尋。如果中間值大於目標值,則把中間下標當成右下標,繼續搜尋。
這是近期在網上用google搜尋“二分法演算法”找到的二分法演算法。結果發現各種各樣的缺陷。
public int erfen()
//二分法尋找
{
int iindex=0; //相當於指標的東西
int istart=0; //
int iend=iarray.length-1;
while(true)
{
icount++;
iindex = (istart+iend)/2;
if(iarray[iindex]<iseek)
{
istart = iindex;
}
else if(iarray[iindex]>iseek)
{
iend = iindex;
}
else
{
break;
}
}
return icount;
}
用一個測試案例就能證明的這個演算法錯誤。
0 1 2 3 4 5尋找5.結果你會發現死迴圈。
很多人認為只要起始值的左值和右值相加為n-1就可以了。其實不然,二分法是10年多的時間才找到了一種正確的演算法。如果你開始的左值設為0並且右值設為n-1,程式很大的程度上會錯。除非你解決了最後的死迴圈問題。
下面的演算法
left
=
-
1
;
right
=
length;
while
(left
<=
right)
...
{
mid
=
(left
+
right)
/
2
;
if
(a[mid]
>
value)
...
{
//
中間值比目標值大
right
=
mid;
}
else
if
(a[mid]
<
value )
...
{
//
中間值比目標值小
left
=
mid;
}
else
...
{
//
找到,中間值等於目標值
return
left;
}
}
return
-
1
;
可以解決上面的0 1 2 3 4 5 尋找5找不到的問題。但是,卻在尋找不存在的數上出了問題。比如6
下面的代碼解決了這個問題:
left
=
-
1
;
right
=
length;
while
(left
+
1
!=
right)
//
注意這句話!!!
...
...
{
mid
=
(left
+
right)
/
2
;
if
(a[mid]
>
value)
...
...
{
//
中間值比目標值大
right
=
mid;
}
else
if
(a[mid]
<
value )
...
...
{
//
中間值比目標值小
left
=
mid;
}
else
...
...
{
//
找到,中間值等於目標值
return
left;
}
}
return
-
1
;
但是上的這段真的解決了所有的問題?如果left + right 超過了整數範圍?
改為下面的代碼:
int
BinarySearch(
int
value)
...
{
int
left
=
-1
;
int
right
=
length
;
int
mid;
while
(left +1!
=
right)
...
{
mid
=
left
+
(right
-
left)
/
2
;
//
注意這裡的寫法
if
(values[mid]
==
value)
...
{
return
mid;
}
else
if
(values[mid]
<
value)
...
{
left
=
mid;
}
else
...
{
right
=
mid;
}
}
return
-
1
;
}
這裡解決了越界問題。但是這段代碼真的沒有問題了嗎?沒有人能保證。除非能用數學證明。
另外還有一種寫法:但是必須特判length==0的情況,否則一定會訪問越界。
int bsearch(int* a, int l, int r,int k)<br />{<br /> int mid = 0;<br /> if(l-r == 0)<br /> return -1;<br /> while(l<=r){<br /> mid = (l+r)/2;<br /> if(a[mid]<k) l = mid+1;<br /> else if(a[mid]>k) r=mid-1;<br /> else return mid;<br /> }<br /> return -1;<br />}<br />