二分查找:binary_search、lower_bound和upper_bound的實現

先來複習一下最經典的大一就學的binary_search。

#include<iostream>
#include<fstream>
#include<algorithm>
using namespace std;
class MY{
    int a;
//public:
    friend ostream& operator <<(ostream& os,const MY &my){
        os<<my.a;return os;
    }
    friend istream& operator >>(istream& is,MY& my){
        is>>my.a;return is;
    }
public:
    MY(int a){this->a=a;}
    MY(){}
    bool operator<(const MY& another){
        return this->a<another.a;
    }
};
template<class T>
int binary_search(T A[],int n,T key)
{
    int low=0,high=n-1;
    while(low<=high){
        int middle=(low+high)/2;
        if(A[middle]<key) low=middle+1;
        else if(key<A[middle]) high=middle-1;
        else return middle;
    }
    return -low-1;
}
/*
10
0 1 2 2 2 4 5 6 6 6
*/
int main()
{
    ifstream fin("10.txt");
    if(!fin) exit(EXIT_FAILURE);
    int n;fin>>n;MY* A=new MY[n];
    for(int i=0;i<n;i++) fin>>A[i];
    cout<<"數組A的內容:";
    for(int i=0;i<n;i++) cout<<A[i]<<" ";
    cout<<endl;
    cout<<"查找"<<endl;
    cout<<"-99:"<<binary_search(A,n,MY(-99))<<endl;
    cout<<"1:"<<binary_search(A,n,MY(1))<<endl;
    cout<<"2:"<<binary_search(A,n,MY(2))<<endl;
    cout<<"3:"<<binary_search(A,n,MY(3))<<endl;
    cout<<"5:"<<binary_search(A,n,MY(5))<<endl;
    cout<<"6:"<<binary_search(A,n,MY(6))<<endl;
    cout<<"99:"<<binary_search(A,n,MY(99))<<endl;
    return 0;
}

然後就到重頭戲。


lower_bound 返回大於等於key的第一個元素的下標。
upper_bound 返回大於key的第一個元素的下標(即小於等於key的最後一個元素的下一個元素的下標)。


設result爲這兩個函數的返回值。


在每次的while迭代前,result的候選範圍爲區間[low,high]。


初始情況:這兩個函數的返回值的可能範圍爲[0,n](數組A的下標範圍是[0,n-1])。


保持:根據A[middle]和key的比較,有3種情況:
①A[middle]=key
對於lower_bound,A[middle](及其前面的元素)可能是等於key的第一個元素,而A[middle+1]至少是等於key的第二個元素。故middle爲候選result,而middle+1不是。故令high=middle。
對於upper_bound,A[middle]可能是小於等於key的最後一個元素,而A[middle]前面的元素則不可能,故它的下一個元素A[middle+1]可能是大於key的第一個元素。故令low=middle+1。


若數組A中不存在與key相等的元素,那麼兩個函數的result是一樣的,即都是大於key的第一個元素的下標,所以在A[middle]和key不相等的情況下,對low和high的設置是一樣的。
②A[middle]<key
而A[middle+1]有可能大於key,且A[middle]之前的元素不可能大於key。故令low=middle+1。
③A[middle]>key
A[middle]有可能是大於key的第一個元素,而A[middle+1]至少是第二個,且A[middle]之前的元素也可能大於key,故令high=middle。


終結:
每次區間[low,high]的長度都會至少減1。當長度減少至1時,結果就出來了。


#include<iostream>
#include<fstream>
#include<algorithm>
using namespace std;
class MY{
    int a;
//public:
    friend ostream& operator <<(ostream& os,const MY &my){
        os<<my.a;return os;
    }
    friend istream& operator >>(istream& is,MY& my){
        is>>my.a;return is;
    }
public:
    MY(int a){this->a=a;}
    MY(){}
    bool operator<(const MY& another){
        return this->a<another.a;
    }
};
template<class T>
int lower_bound(T A[],int n,T key)
{
    int low=0,high=n;
    while(low<high){
        int middle=(low+high)/2;
        if(A[middle]<key) low=middle+1;
        else high=middle;
    }
    return low;
}
/*
10
0 1 2 2 2 4 5 6 6 6
*/
int main()
{
    ifstream fin("10.txt");
    if(!fin) exit(EXIT_FAILURE);
    int n;fin>>n;MY* A=new MY[n];
    for(int i=0;i<n;i++) fin>>A[i];
    cout<<"數組A的內容:";
    for(int i=0;i<n;i++) cout<<A[i]<<" ";
    cout<<endl;
    cout<<"查找"<<endl;
    cout<<"-99:"<<lower_bound(A,n,MY(-99))<<endl;
    cout<<"1:"<<lower_bound(A,n,MY(1))<<endl;
    cout<<"2:"<<lower_bound(A,n,MY(2))<<endl;
    cout<<"3:"<<lower_bound(A,n,MY(3))<<endl;
    cout<<"5:"<<lower_bound(A,n,MY(5))<<endl;
    cout<<"6:"<<lower_bound(A,n,MY(6))<<endl;
    cout<<"99:"<<lower_bound(A,n,MY(99))<<endl;
    return 0;
}

#include<iostream>
#include<fstream>
#include<algorithm>
using namespace std;
class MY{
    int a;
//public:
    friend ostream& operator <<(ostream& os,const MY &my){
        os<<my.a;return os;
    }
    friend istream& operator >>(istream& is,MY& my){
        is>>my.a;return is;
    }
public:
    MY(int a){this->a=a;}
    MY(){}
    bool operator<(const MY& another){
        return this->a<another.a;
    }
};
template<class T>
int upper_bound(T A[],int n,T key)
{
    int low=0,high=n;
    while(low<high){
        int middle=(low+high)/2;
        if(key<A[middle]) high=middle;
        else low=middle+1;
    }
    return low;
}
/*
10
0 1 2 2 2 4 5 6 6 6
*/
int main()
{
    ifstream fin("10.txt");
    if(!fin) exit(EXIT_FAILURE);
    int n;fin>>n;MY* A=new MY[n];
    for(int i=0;i<n;i++) fin>>A[i];
    cout<<"數組A的內容:";
    for(int i=0;i<n;i++) cout<<A[i]<<" ";
    cout<<endl;
    cout<<"查找"<<endl;
    cout<<"-99:"<<upper_bound(A,n,MY(-99))<<endl;
    cout<<"1:"<<upper_bound(A,n,MY(1))<<endl;
    cout<<"2:"<<upper_bound(A,n,MY(2))<<endl;
    cout<<"3:"<<upper_bound(A,n,MY(3))<<endl;
    cout<<"5:"<<upper_bound(A,n,MY(5))<<endl;
    cout<<"6:"<<upper_bound(A,n,MY(6))<<endl;
    cout<<"99:"<<upper_bound(A,n,MY(99))<<endl;
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章