欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C語言基礎(chǔ)之二分查找知識(shí)最全匯總

 更新時(shí)間:2021年04月29日 14:18:14   作者:峽谷金城武  
這篇文章主要介紹了C語言基礎(chǔ)之二分查找知識(shí)最全匯總,文中有非常詳細(xì)的二分查找基礎(chǔ)知識(shí)詳解,對(duì)正在學(xué)習(xí)C語言基礎(chǔ)的小伙伴們有非常好的幫助,需要的朋友可以參考下

一、前言

在自學(xué)二分查找的過程中我想到了一些變化問題,有的自己就慢慢理解了,有的在網(wǎng)上找到了答案,奈何沒有找到想要的總結(jié)歸納。我就斗膽自己寫了一篇,號(hào)稱史上最全。希望和我一樣的伙伴可以少走一點(diǎn)彎路。

二分查找憑借其低時(shí)間復(fù)雜度O(log(n))成為了各個(gè)蒟蒻的入門知識(shí),但是其衍生出的各種題目相較原題目而言就沒有那么容易求解,以下借用c語言實(shí)現(xiàn)二分查找算法及其衍生。二分查找僅適用于事先已經(jīng)排好序的順序表。其基本思路就是每次取中間數(shù),如果中間數(shù)大于所求數(shù)就向上查找,反之向下。

二、原始二分查找

1.在有序數(shù)組中尋找一個(gè)數(shù)所在下標(biāo)。

int main(){
    int arr[] = {1,2,3,4,5,6,7,8,9};
    int left,right,fin;
    fin = 3;
    left = 0;right = sizeof(arr)/sizeof(arr[0])-1;
 
    while(left <= right) {
        int mid;
        mid = (left+right) / 2;
        if (arr[mid] == fin) {
            printf("找到了:%d\n", mid);
            return 0;
        }
        if (mid < fin)
            left = mid+1;
        else if (mid > fin)
            right = mid-1;
 
    }
    printf("沒找到");
    return 0;
}

對(duì)于這種基本的排序問題,我們通過判斷mid變量與key的大小對(duì)有序數(shù)組進(jìn)行二分。

當(dāng)查找過程中,會(huì)出現(xiàn)key值下標(biāo)坐落在left或right上時(shí)的情況,

以下用left舉例

當(dāng)left = key時(shí),一個(gè)顯然的結(jié)論,此時(shí)arr[mid]無法等于key。其所作工作為減小right,進(jìn)一步縮進(jìn)范圍,直到right = left或right = left+1,此時(shí)范圍縮小到最小,mid = left。輸出mid的值即為所求下標(biāo)。

我們當(dāng)然可以在left和right = key時(shí)直接輸出key的下標(biāo),但是這樣會(huì)造成多次比較。

三、二分查找的變化之?dāng)?shù)組元素重復(fù)

對(duì)于二分查找而言,會(huì)出現(xiàn)數(shù)組元素重復(fù)的情況,以下問題的求解建立在數(shù)組元素重復(fù)的情況下:

1.返回匹配數(shù)key的最小下標(biāo)

#include <stdio.h>
 
int main() {
    int arr[] = {1,3,3,3,3,4,5,6,7};
    int left,right,lenght,key;
    key = 3;
    left = 0;
    lenght = sizeof(arr)/sizeof(arr[0]);
    right = lenght -1;
    while(left <= right){
        //等于的條件不能忽略
        int mid = (left+right)/2;
        if (arr[mid] < key)
            left = mid + 1;
            //目的是用left來尋找key點(diǎn),不考慮mid = key的情況
        else
            right = mid - 1;
    }
    if ((left < lenght)&&(arr[left] == key))
        printf("%d\n",left);
    return 0;
}

當(dāng)arr[mid] == key 時(shí),此時(shí)直接輸出,則無法達(dá)到最小坐標(biāo)。所以我們需要移動(dòng)left或right。對(duì)于移動(dòng)left而言,顯然移動(dòng)后left將大于mid,更不可能找到最小坐標(biāo)。所以需要移動(dòng)right,讓left逐漸逼近key的最小下標(biāo)。

當(dāng)arr[mid] > key時(shí),此時(shí)需要移動(dòng)right,所以此時(shí)不會(huì)出現(xiàn)left = key的情況

當(dāng)arr[mid] < key時(shí),此時(shí)需要移動(dòng)left,前面已經(jīng)知道m(xù)id<key,當(dāng)left = mid + 1時(shí),(其實(shí)類似于單調(diào)函數(shù)的求值)arr[mid] < arr[left] <=key

與原題對(duì)比,我們可以發(fā)現(xiàn),只有arr[mid] == key 時(shí)產(chǎn)生了變化,這里有一個(gè)顯然的結(jié)論,對(duì)于arr[mid] == key ,當(dāng)求最小下標(biāo)時(shí),我們需要下標(biāo)left<mid,所以只能移動(dòng)right,當(dāng)求最大下標(biāo)時(shí),我們需要right>mid,所以只能移動(dòng)left。

2.返回匹配數(shù)的最大下標(biāo)

#include <stdio.h>
 
int main() {
    int arr[] = {1,3,3,3,3,4,5,6,7};
    int left,right,lenght,key;
    key = 3;
    left = 0;
    lenght = sizeof(arr)/sizeof(arr[0]);
    right = lenght -1;
    while(left <= right){
        int mid = (left+right)/2;
        if (arr[mid] <= key)
            left = mid + 1;
        else
            right = mid - 1;
    }
    if ((right >= 0)&&(arr[right] == key))
        printf("%d\n",right);
    return 0;
}

3.返回第一個(gè)大于匹配數(shù)的下標(biāo)

#include <stdio.h>
 
int main() {
    int arr[] = {1,1,1,1,1,4,5,6,7};
    int left,right,lenght,key;
    key = 3;
    left = 0;
    lenght = sizeof(arr)/sizeof(arr[0]);
    right = lenght -1;
    while(left <= right){
        int mid = (left+right)/2;
        if (arr[mid] < key)
            left = mid + 1;
        else
            right = mid - 1;
    }
        printf("%d\n",arr[left]);
    return 0;
}

這個(gè)問題,比較簡單,把之前的if條件注釋掉就好了。=_=因?yàn)槲覀冊(cè)谘h(huán)過程中如果沒有找到,left會(huì)自己停在第一個(gè)大于key的坐標(biāo)上。

4.查找某個(gè)數(shù)的出現(xiàn)次數(shù)

這個(gè)問題就比較進(jìn)階,一開始在一篇介紹二分查找的文章里看到求出現(xiàn)次數(shù),怎么想也聯(lián)系不到二分查找。最后在網(wǎng)上找到了別人寫的代碼,其實(shí)就是兩次二分查找,但是試了好幾次也沒有寫對(duì),看來我的蒟蒻路還有很長。

四、輪轉(zhuǎn)循環(huán)

何為輪轉(zhuǎn)(循環(huán))有序數(shù)組,就比如說{7,8,9,0,1,2,3,4,5,6}就是一個(gè)輪轉(zhuǎn)數(shù)組,其最小值不在[0]點(diǎn)。對(duì)于這樣的數(shù)組是否可以使用二分查找,?

對(duì)于這種問題,我們需要考慮的是他的順序起點(diǎn),以{7,8,9,0,1,2,3,4,5,6}為例,他的順序起點(diǎn)為a[3] = 0;

(其實(shí)把它理解成為一個(gè)分段函數(shù)最容易,但是csdn不好寫數(shù)學(xué)表達(dá)式,不好畫圖,有興趣的蒟蒻可以私信我)

#include <stdio.h>
int find(int arr[],int left,int right,int key) {
//傳參a[]是所求數(shù)組,left,right為所求左右下標(biāo),key是所求元素
    while (left <= right) {
        int mid = (left + right) / 2;
        if(arr[mid] > key){
            if(arr[mid] < arr[right])//當(dāng)此式成立時(shí)表明元素順序起點(diǎn)在mid左邊。
                right = mid - 1;
            else {//元素順序起點(diǎn)在mid右邊,但是key有可能在mid左邊有可能在mid右邊
                if (key > arr[left])//在左邊
                    right = mid - 1;
                else
                    left = mid + 1;
            }
        }
        else if(arr[mid] < key){
            if(arr[mid] > arr[left])//在mid左邊是遞增的(順序起點(diǎn)在[0]或右邊)
                left = mid + 1;
            else{//順序起點(diǎn)在左邊且不在[0]上
                if (key > arr[right])//在mid左邊
                    right = mid - 1;
                else
                    left = left + 1;
            }
        }
        else//當(dāng)相等時(shí)直接返回mid
           return mid;
 
    }
 
}
int main() {
    int left,right,key,mid;
    int arr[] = {7,8,9,0,1,2,3,4,5,6};
    left = 0;
    right =( sizeof(arr)/sizeof(arr[0]) ) - 1;
    key = 4;
    mid = find(arr,left,right,key);
    printf("峽谷吳彥祖 %d",mid);
    return 0;
}

五、楊氏矩陣

在劍指offer的項(xiàng)目練習(xí)上,有在楊氏矩陣中對(duì)一個(gè)數(shù)進(jìn)行查找的案例。題中所給出的解題思路是利用楊氏矩陣每行遞增,每列遞增的性質(zhì)每次排除某行或某列。而在我的實(shí)踐過程中,其可以采用二分查找的思路,對(duì)大規(guī)模的矩陣進(jìn)行更加優(yōu)化的查找。以下是此方法的代碼:

int yang_matrix_2(int arr[X][Y],int num) {
    int x = 0;
    int y = Y;
    int a = x;
    int b = y;
    do{
       a = x;b = y;
        if (arr[x][y] > num) {//在列上進(jìn)行折半查找
            int left = 0;
            int right = Y-1;
            while (left <= right){
                int mid = (((left ^ right) >> 1)+(left & right));
                if (arr[x][mid] > num)
                    right = mid - 1;
                else {
                    if (arr[x][mid] < num)
                        left = mid + 1;
                    else
                        return 1;}
            }
            y = left;
            x--;
        }
        else{
            if(arr[x][y] < num){
                int left = 0;
                int right = X-1;
                while (left <= right){
                    int mid = (((left ^ right) >> 1)+(left & right));
                    if (arr[mid][y] > num)
                        right = mid - 1;
                    else {if (arr[mid][y] < num)
                            left = mid + 1;
                        else
                            return 1;}
                }
                x = right;
                ++y;
            }//在行上進(jìn)行折半查找
            else
                return 1;
        }
    }while ((x != a) && (y != b));
    return 0;
}

六、用二叉樹來描述二分查找

二分查找過程可用二叉樹來描述:把當(dāng)前查找區(qū)間的中間位置上的結(jié)點(diǎn)作為根,左子表和右子表中的結(jié)點(diǎn)分別作為根的左子樹和右子樹。

由此得到的二叉樹,稱為描述二分查找的判定樹(Decision Tree)或比較樹(Comparison Tree)。以下圖為例

七、二分查找的概率問題

我們需要引入一個(gè)概念叫做平均查找長度ASL,為確定記錄在查找表中的位置,需和給定值進(jìn)行比較的關(guān)鍵字個(gè)數(shù)的期望值稱為查找算法在查找成功時(shí)的平均查找長度()。二分查找的ASL = log2(n+1)-1。

到此這篇關(guān)于C語言基礎(chǔ)之二分查找知識(shí)最全匯總的文章就介紹到這了,更多相關(guān)C語言二分查找匯總內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 基于Matlab實(shí)現(xiàn)水波倒影特效的制作

    基于Matlab實(shí)現(xiàn)水波倒影特效的制作

    這篇文章主要介紹了如何利用Matlab制作出水波倒影的特效,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)Matlab有一定幫助,需要的可以參考一下
    2022-03-03
  • C++有限狀態(tài)機(jī)實(shí)現(xiàn)詳解

    C++有限狀態(tài)機(jī)實(shí)現(xiàn)詳解

    這篇文章主要為大家詳細(xì)介紹了C++有限狀態(tài)機(jī)的相關(guān)資料,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-10-10
  • C語言 數(shù)與串之間轉(zhuǎn)換的方法

    C語言 數(shù)與串之間轉(zhuǎn)換的方法

    C語言 數(shù)與串之間轉(zhuǎn)換的方法,需要的朋友可以參考一下
    2013-05-05
  • 嵌入式項(xiàng)目使用C語言結(jié)構(gòu)體位段特性實(shí)現(xiàn)斷言宏校驗(yàn)數(shù)據(jù)范圍有效性的方法

    嵌入式項(xiàng)目使用C語言結(jié)構(gòu)體位段特性實(shí)現(xiàn)斷言宏校驗(yàn)數(shù)據(jù)范圍有效性的方法

    今天小編就為大家分享一篇關(guān)于嵌入式項(xiàng)目使用C語言結(jié)構(gòu)體位段特性實(shí)現(xiàn)斷言宏校驗(yàn)數(shù)據(jù)范圍有效性的方法,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2018-12-12
  • C語言學(xué)生成績管理系統(tǒng)小設(shè)計(jì)

    C語言學(xué)生成績管理系統(tǒng)小設(shè)計(jì)

    這篇文章主要為大家詳細(xì)介紹了C語言學(xué)生成績管理系統(tǒng)小設(shè)計(jì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • 淺談C++流庫的基本結(jié)構(gòu)

    淺談C++流庫的基本結(jié)構(gòu)

    本文主要介紹了淺談C++流庫的基本結(jié)構(gòu),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • C++空類默認(rèn)函數(shù)詳細(xì)解析

    C++空類默認(rèn)函數(shù)詳細(xì)解析

    如果你只是聲明一個(gè)空類,不做任何事情的話,編譯器會(huì)自動(dòng)為你生成一個(gè)默認(rèn)構(gòu)造函數(shù)、一個(gè)拷貝默認(rèn)構(gòu)造函數(shù)、一個(gè)默認(rèn)拷貝賦值操作符和一個(gè)默認(rèn)析構(gòu)函數(shù)
    2013-10-10
  • C++如何通過ostringstream實(shí)現(xiàn)任意類型轉(zhuǎn)string

    C++如何通過ostringstream實(shí)現(xiàn)任意類型轉(zhuǎn)string

    再使用整型轉(zhuǎn)string的時(shí)候感覺有點(diǎn)棘手,因?yàn)閕toa不是標(biāo)準(zhǔn)C里面的,而且即便是有itoa,其他類型轉(zhuǎn)string不是很方便。后來去網(wǎng)上找了一下,發(fā)現(xiàn)有一個(gè)好方法
    2013-09-09
  • C++ 如何實(shí)現(xiàn)順序棧(使用模板類)

    C++ 如何實(shí)現(xiàn)順序棧(使用模板類)

    這篇文章主要介紹了C++ 如何實(shí)現(xiàn)順序棧(使用模板類),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-07-07
  • C語言中do-while語句的2種寫法示例

    C語言中do-while語句的2種寫法示例

    這篇文章主要給大家介紹了關(guān)于C語言中do-while語句的2種寫法示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07

最新評(píng)論