深入理解CPP與C中bsearch函式的用法
·使用besearch函式的前提(一些廢話)
首先讓我們先亮出二分法的定義:
https://baike.baidu.com/item/二分法/1364267
以及二分法實現的方法:
https://blog.csdn.net/sufeiboy/article/details/54401257
這些應該是使用二分查詢前需要了解的知識,綜上我們可以得出:使用besearch前應該先將目標陣列進行一定規律的排序,事實上大部分時候我們會使用庫中自帶的qsort函式進行排序。
·besearch函式的函式原型解析
(資料源於網路)
void *bsearch(const void *key, const void *base, size_t num, size_t size, int (*cmp)(const void *, const void *));
解釋一下引數
key: 為要查詢的元素的地址
base: 指向進行查詢的陣列的開始地址
num: 為想要查詢的範圍,即在多少個數中進行二分查詢
size:陣列中每個元素的大小,一般用sizeof()表示
cmp:比較兩個元素的函式,定義比較規則。這裡我們可以類比qsort,首先對於這樣一個cmp:
int cmp(const void *p1,const void *p2);
其中p1始終指向的是key的地址,而p2指向的是besearch所查詢的數組裡的傳遞過來的元素
其次我們知道qsort對於cmp函式的比較返回值的處理是當返回值為正則交換兩個元素,而對於bsearch則為當返回值為0則認為查詢到了目標元素。當返回值為正數則besearch會向後進行二分查詢,返回值為負數將會向前進行二分查詢。
關於besearch的返回值: besearch在找到元素後將返回陣列中滿足cmp條件的這個數的地址,但是這個地址是void *型別的,如果我們不加以型別轉換就無法使用。而如果沒有找到對應元素則會返回NULL指標,我們可以通過判斷返回值的型別得到元素是否在陣列中存在。
關於besearch的陷阱: 當陣列中存在多個匹配元素時,besearch不能保證返回的指標一定指向某一個特定的元素,此時besearch只能用於證明陣列內是否含有特定元素
·bserach的使用例項
#include <stdio.h> #include <stdlib.h> int cmp(const void *p1,const void *p2) { int a=*(int *)p1,b=*(int *)p2;//為了清楚說明進行臨時轉化儲存 return a-b;//僅當a=b時返回0,說明查詢到了 } int main(int argc, char const *argv[]) { int arry[100]; for(int i=1;i<=100;i++) arry[i-1]=i; int *ans;//用於接受查詢的結果 int key; scanf("%d",&key); ans=(int *)bsearch(&key,arry,100,sizeof(int),cmp);//記得對結果進行轉換 if (ans!=NULL) printf("The key:%d exists.The pointer is %X.",key,ans); else printf("The key doesn't exists\n"); return 0; }
四次執行例項:
輸入: 13 輸出: The key:13 exists.The pointer is 61FD74. 輸入: 60 輸出: The key:60 exists.The pointer is 61FD9C. 輸入: 0 輸出: The key doesn't exists 輸入: 101 輸出 The key doesn't exists
·bserach的使用例項
我們知道,上述的陣列是一個升序陣列,那麼考慮一下情況,如果arry是一個 100 99 98…… 2 1的降序陣列此時我們該如何編寫cmp函式
其實很簡單,根據cmp返回值對besearch的影響,我只需把return語句重寫
原本: int cmp(const void *p1,const void *p2) { int a=*(int *)p1,b=*(int *)p2; return a-b; } 現在 int cmp(const void *p1,const void *p2) { int a=*(int *)p1,b=*(int *)p2; return b-a; }
是不是很像qsort的處理方式呢
更進一步的,如果我們要尋找這樣一個元素它恰好是key的三倍,那麼我們可以這麼寫:
int cmp(const void *p1,const void *p2) { int a=*(int *)p1,b=*(int *)p2; return 3*a-b;//這裡預設arry進行升序排列 }
至此,關於besearch的基本部分便已陳述完畢,實際上我們可以通過besearch進行更復雜的查詢,正如網上很多的關於qsort對結構體進行一級甚至多級排序,besearch也同樣可以。
本文在此結束,但讀者可以自行去探索。