細說「二分查詢」

2022-03-12 01:36:34 字數 4057 閱讀 1295

前言:

二分演算法很常見,也很簡單。但確實很高效!有了它,我們常常可以避免"暴力"!

先貼一段**,大家看看有沒有問題?

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.如果待查詢...