前言:
二分演算法很常見,也很簡單。但確實很高效!有了它,我們常常可以避免"暴力"!
先貼一段**,大家看看有沒有問題?
1分析:當你拿上述的**進行測試的時候,一切正常,看似風平浪靜...那麼,問題在哪兒呢~int binarysearch(int *arr,int l,int r,int
key)else
if(arr[m]>key)else11}
12return -1
;13 }
1 #include2測試結果:#define n 534
/*'l'起始下標,'r'結束下標*/5
int binarysearch(int *arr,int l,int r,int
key)else
if(arr[m]>key)else15}
16return -1;17
}18intmain();
20 printf("
%d\n
",binarysearch(arr,0,n,1
));21 printf("
%d\n
",binarysearch(arr,0,n,3
));22 printf("
%d\n
",binarysearch(arr,0,n,100
));23
return0;
24 }
}17//已知存在一或多個『key』,求key的最小下標
18int lowerbound(int *arr,int l,int r,int
key)else
if(arr[m]>key)else28}
29return
l;30}31
32int upperbound(int *arr,int l,int r,int
key)else
if(arr[m]>key)else45}
46return
l;47}48
intmain();
50 printf("
--------lower--------\n");
51 printf("
%d\n
",lowerbound(arr,0,n-1,1
));52 printf("
%d\n
",lowerbound(arr,0,n-1,3
));53 printf("
%d\n
",lowerbound(arr,0,n-1,11
));54 printf("
%d\n
",lowerbound(arr,0,n-1,0
));55 printf("
--------upper--------\n");
56 printf("
%d\n
",upperbound(arr,0,n-1,1
));57 printf("
%d\n
",upperbound(arr,0,n-1,3
));58 printf("
%d\n
",upperbound(arr,0,n-1,11
));59 printf("
%d\n
",upperbound(arr,0,n-1,100
));60
return0;
61 }
上述**的實現過程如下圖:
測試結果:
分析:
在有序陣列中,本來我們大可通過一次遍歷對」key「進行計數,時間複雜度:o(n);但有了二分查詢!我們下面還是考慮如何提高效率吧~
首先,我們都知道在乙個有序數列中,假如同時存在多個」key「,那麼用我們上面binarysearch()函式返回的是數列中其中乙個key的下標(具有隨機性,跟key在數列的位置有關!)
怎麼求解呢?其實,我們上面的例子就是為這一小節的內容準備的。但是我們需要考慮2種情況,一種是要查詢的key本來就不存在數列中,第二種是key存在數列中。保險一點的做法是,我們先用普通的二分查詢判斷一下是否存在,若存在再使用上一小節的lowerbound()和upperbound()方法。但,巧妙的是不管key在不在我們都可以使用上一小節的方法。因為我們要計算的是差值,不是具體的下標!所以,
方法一:利用lowerbound()和upperbound()算出數列中key的最大和最小座標i,j之後,進行相減;
方法二:只需要lowerbound()方法。這裡應用了一點小技巧,即:要查詢數列中有多少個」key「,那麼我利用lowerbound()函式分別得到"key"和」(key+1)「的起始座標值(不管」key+1「實際存不存在),兩者相減即是答案!
}17//已知存在一或多個『key』,求key的最小下標
18int lowerbound(int *arr,int l,int r,int
key)else
if(arr[m]>key)else28}
29return
l;30}31
32int upperbound(int *arr,int l,int r,int
key)else
if(arr[m]>key)else45}
46return
l;47}48
int countx(int *a,int l,int r,int
key)
51int
main();
53 printf("
需要統計個數的x存在於陣列中:\n");
54 printf("
方式一輸出:%d\n
",countx(arr,0,n-1,3
));55 printf("
方式二輸出:%d\n
",lowerbound(arr,0,n-1,3+1)-lowerbound(arr,0,n-1,3
));56
57 printf("
需要統計個數的x不存在於陣列中:\n");
58 printf("
方式一輸出:%d\n
",countx(arr,0,n-1,2
));59 printf("
方式二輸出:%d\n
",lowerbound(arr,0,n-1,2+1)-lowerbound(arr,0,n-1,2
));60
61return0;
62 }
測試結果:
注意:
迭代二分查詢二分查詢
在寫這篇文章之前,已經寫過了幾篇關於改迭代二分查詢主題的文章,想要了解的朋友可以去翻一下之前的文章 bentley在他的著作 writing correct programs 中寫道,90 的計算機專家不能在2小時內寫出完整確正的二分搜尋演算法。難怪有人說,二分查詢道理單簡,甚至小學生都能明確。不過...
1128 二分 二分查詢
時間限制 10000ms 單點時限 1000ms 記憶體限制 256mb 描述nettle最近在玩 艦 因此nettle收集了很多很多的船 這裡我們假設nettle氪了很多金,開了無數個船位 去除掉重複的船之後,還剩下n 1 n 1,000,000 種不同的船。每一艘船有乙個稀有值,任意兩艘船的稀有...
二分查詢及變種二分查詢
二分查詢也稱折半查詢 binary search 它的查詢效率很好。二分查詢有乙個要求是必須採用順序儲存結構,而且表種的元素是有序的。只有滿足這個條件我們才能使用二分查詢。查詢條件 查詢區域的左邊界,小於等於查詢區域的右邊界 查詢過程 1.迴圈條件 查詢條件 2.計算序列中間下標位置 3.如果待查詢...