1. 程式人生 > >深入理解CPP與C中bsearch函式的用法

深入理解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會向後進行二分查詢,返回值為負數將會向前進行二分查詢。

簡單的記憶方法便是:升序陣列返回p1-p2,降序陣列返回p2-p1(這裡建議看完使用例項後再看)

關於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也同樣可以。
本文在此結束,但讀者可以自行去探索。