二分查找—lower_bound 、upper_bound 、binary_search

28 篇文章 0 订阅

STL中关于二分查找的函数有三个lower_bound 、upper_bound 、binary_search 。这三个函数都运用于有序区间(当然这也是运用二分查找的前提)。

       其中如果寻找的value存在,那么lower_bound返回一个迭代器指向其中第一个这个元素。upper_bound返回一个迭代器指向其中最后一个这个元素的下一个位置(明确点说就是返回在不破坏顺序的情况下,可插入value的最后一个位置)。如果寻找的value不存在,那么lower_bound和upper_bound都返回“假设这样的元素存在时应该出现的位置”。要指出的是lower_bound和upper_bound在源码中只是变换了if—else语句判定条件的顺序,就产生了最终迭代器位置不同的效果。

       binary_search试图在已排序的[first,last)中寻找元素value,若存在就返回true,若不存在则返回false。返回单纯的布尔值也许不能满足需求,而lower_bound、upper_bound能提供额外的信息。事实上由源码可知binary_search便是利用lower_bound求出元素应该出现的位置,然后再比较该位置   的值与value的值。该函数有两个版本一个是operator< ,另外一个是利用仿函数comp进行比较。

######################################################################

std::sort      对vector成员进行排序;

std::sort(v.begin(),v.end(),compare);

std::lower_bound 在排序的vector中进行二分查找,查找第一大于等于;
std::lower_bound(v.begin(),v.end(),v.element_type_obj,compare);

std::upper_bound 在排序的vector中进行二分查找,查找第一个大于;
std::upper_bound(v.begin(),v.end(),v.element_type_obj,compare);

std::binary_search 在排序的vector中进行二分查找;
std:: binary_search(v.begin(),v.end(),v.element_type_obj,compare );

std::unique 将排序的vector
vector<element_type>::iterator iter = std::unique(v.begin(),v.end(),compare);
v.resize(iter-v.begin());

std::for_each 将迭代器指向区间的内容调用指定的函数
void show(element_type& obj);
std::for_each(v.begin(),v.end(),show);
这里也可以:
strcut showclass
{
       void  operator ()(element_type& obj){
                 //具体操作......
       }
}showobj;
std::for_each(v.begin(),v.end(),showobj);

std::random_shuffle将迭代器指向的内容内容打散
std::random_shuffle(v.begin(),v.end());
或:
// random generator function:
ptrdiff_t myrandom (ptrdiff_t i) { return rand()%i;}
// pointer object to it:
ptrdiff_t (*p_myrandom)(ptrdiff_t) = myrandom;
random_shuffle ( myvector.begin(), myvector.end(), p_myrandom);

具体使用:
std::sort使用:
              std::sort(vectorobj.begin(),vectorobj.end(),compare_fun);
std:: lower_bound 使用:
      std:: lower_bound  ( vectorobj.begin(),vectorobj.end(),比较对象,compare_fun );
     比较对象的类型和vectorobj的成员类型一样。
示例:
#include <vector>
#include <algorithm>
#include <algorithm>
#include <iostream>
struct Student
{
    int age;
};
//sort和lower_bound使用比较函数的原型:
//boo function(const vector的成员类型 lit,const vector的成员类型 rit);
bool CompareOperation(const Student& lit,const Student& rit)     
{
    if(lit.age<rit.age){
        return true;
    }else{
        return false;
    }
}
int main(int argc,char *argv[])
{
    std::vector<Student> stuvec;
    Student a;
    a.age = 5;
    stuvec.push_back(a);
    Student b;
    b.age = 6;
    stuvec.push_back(b);
    Student c;
    c.age = 4;
    stuvec.push_back(c);
    Student d;
    d.age = 7;
    stuvec.push_back(d);
    std::cout<<"befort sort"<<std::endl;
    for(size_t index=0;index<stuvec.size();index++){
        std::cout<<stuvec[index].age<<std::endl;
    }
    std::sort(stuvec.begin(),stuvec.end(),CompareOperation);
    std::cout<<"after sort"<<std::endl;
    for(size_t index=0;index<stuvec.size();index++){
        std::cout<<stuvec[index].age<<std::endl;
    }
    std::cout<<"binary search"<<std::endl;
    std::vector<Student>::iterator iter = 
        std::lower_bound(stuvec.begin(),stuvec.end(),b,CompareOperation);
    if(iter != stuvec.end()){
        std::cout<<iter->age<<std::endl;
    }
    return 0;
}
运行结果:
stl算法库参看:
示例代码:
// lower_bound/upper_bound example
#include <iostream>     // std::cout
#include <algorithm>    // std::lower_bound, std::upper_bound, std::sort
#include <vector>       // std::vector
int main () {
  int myints[] = {10,20,30,30,20,10,10,20};
  std::vector<int> v(myints,myints+8);           // 10 20 30 30 20 10 10 20
  std::sort (v.begin(), v.end());                // 10 10 10 20 20 20 30 30
  std::vector<int>::iterator low,up;
  low=std::lower_bound (v.begin(), v.end(), 20); // 第一个   >= 20 的元素的迭代器
  up= std::upper_bound (v.begin(), v.end(), 20); // 第一个   > 20  的元素的迭代器  
  std::cout << "lower_bound at position " << (low- v.begin()) << '\n';
  std::cout << "upper_bound at position " << (up - v.begin()) << '\n';
  return 0;
}
// 使用std::unique可以将有序的vector中的成员去重:
#include <iostream>     // std::cout
#include <algorithm>    // std::lower_bound, std::upper_bound, std::sort,std::unique, std::for_each
#include <vector>       // std::vector
void show(const int& i)
{
    std::cout<<i<<std::endl;
}
int main () {
    int myints[] = {10,20,30,30,20,10,10,20};
    std::vector<int> v(myints,myints+8);           // 10 20 30 30 20 10 10 20
    std::sort (v.begin(), v.end());                // 10 10 10 20 20 20 30 30
    std::vector<int>::iterator iter = std::unique(v.begin(),v.end());
    v.resize(iter - v.begin());
    std::for_each(v.begin(),v.end(),show);
    return 0;
}
使用std::binary_search对vector进行排序;
// binary_search example
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
bool myfunction (int i,int j) { return (i<j); }
int main () {
  int myints[] = {1,2,3,4,5,4,3,2,1};
  vector<int> v(myints,myints+9);                         // 1 2 3 4 5 4 3 2 1
  // using default comparison:
  sort (v.begin(), v.end());

  cout << "looking for a 3... ";
  if (binary_search (v.begin(), v.end(), 3))
    cout << "found!\n"; else cout << "not found.\n";

  // using myfunction as comp:
  sort (v.begin(), v.end(), myfunction);

  cout << "looking for a 6... ";
  if (binary_search (v.begin(), v.end(), 6, myfunction))
    cout << "found!\n"; else cout << "not found.\n";

  return 0;
}
参看:http://www.cplusplus.com/reference/algorithm/binary_search/?kw=binary_search
std::random_shuffle将指定的迭代器区间的内容随机打散:
// random_shuffle example
#include <iostream>
#include <algorithm>
#include <functional>
#include <vector>
#include <ctime>
#include <cstdlib>
using namespace std;

// random generator function:
ptrdiff_t myrandom (ptrdiff_t i) { return rand()%i;}

// pointer object to it:
ptrdiff_t (*p_myrandom)(ptrdiff_t) = myrandom;

int main () {
  srand ( unsigned ( time (NULL) ) );
  vector<int> myvector;
  vector<int>::iterator it;

  // set some values:
  for (int i=1; i<10; ++i) myvector.push_back(i); // 1 2 3 4 5 6 7 8 9

  // using built-in random generator:
  random_shuffle ( myvector.begin(), myvector.end() );

  // using myrandom:
  random_shuffle ( myvector.begin(), myvector.end(), p_myrandom);

  // print out content:
  cout << "myvector contains:";
  for (it=myvector.begin(); it!=myvector.end(); ++it)
    cout << " " << *it;

  cout << endl;

  return 0;
}
###############################区间查找的实现######################################

void TransformIntoScheduleConfig(OS::CommonPolicy *timesetting,   
    ScheduleConfiguration *scheduleconfig) {
    OS::TimeRange *timerangesetting = NULL;
    ScheduleConfiguration::TimeRange timerange;
    ywb_uint32_t size = 0;
    ywb_uint32_t pos = 0;
    ywb_uint32_t hour = 0;
    ywb_uint32_t min = 0;
    string *time;
    string tmp;

    size = timesetting->time_range_size();
    for (ywb_uint32_t i = 0; i < size; i++) {
        timerangesetting = timesetting->mutable_time_range(i);
        time = timerangesetting->mutable_str_time(0);
        pos = time->find(':');
        tmp = time->substr(0, pos);
        hour = std::atoi(tmp.c_str());
        tmp = time->substr(pos + 1, time->size() - pos - 1);
        min = std::atoi(tmp.c_str());
        timerange.mStart = hour * 3600 + min * 60;
        time = timerangesetting->mutable_str_time(1);
        pos = time->find(':');
        tmp = time->substr(0, pos);
        hour = std::atoi(tmp.c_str());
        tmp = time->substr(pos + 1, time->size() - pos - 1);
        min = std::atoi(tmp.c_str());
        timerange.mEnd = hour * 3600 + min * 60;
        scheduleconfig->mRangeList.push_back(timerange);
    }
    scheduleconfig->mWeekDays = 0;
    size = timesetting->weekday_size();
    for (ywb_uint32_t i = 0; i < size; i++) {
        YWB_ASSERT(timesetting->weekday(i) >= 0);
        YWB_ASSERT(timesetting->weekday(i) <= 6);
        scheduleconfig->mWeekDays |= (0x01 << (7 - timesetting->weekday(i)));
    }
}
==============
ywb_bool_t TimeIsScheduled(ScheduleConfiguration *schedule)
{
    ywb_time_exp_t exptime;
    ywb_status_t err = YWB_SUCCESS;
    ywb_uint32_t seconds = 0;
    ScheduleConfiguration::TimeRange range;
    std::vector<ScheduleConfiguration::TimeRange>::iterator iter;

    err = ywb_time_exp_lt(&exptime, ywb_time_now());
    if (YWB_SUCCESS != err) {
        return ywb_true;
    }
    if (!((0x80 >> exptime.tm_wday) & schedule->mWeekDays)) {
        return ywb_false;
    }
    seconds = exptime.tm_hour*3600 + exptime.tm_min*60 + exptime.tm_sec;
    range.mStart = seconds;
    range.mEnd = seconds;
    iter = std::lower_bound(schedule->mRangeList.begin(), schedule->mRangeList.end(), range);
    if (schedule->mRangeList.end() == iter) {
        return ywb_false;
    }
    if (iter->mStart > seconds || iter->mEnd < seconds) {
        return ywb_false;
    }
    return ywb_true;
}
===============
class ScheduleConfiguration {
public:
    struct TimeRange
    {
        public:
            ywb_uint32_t mStart;
            ywb_uint32_t mEnd;
        public:
            bool operator<(const TimeRange &range)
            {
                if(range.mStart == range.mEnd) {
                    return mEnd < range.mEnd;
                } else {
                    if(mStart == mEnd) {
                        return mEnd <= range.mEnd;
                    } else {
                        return mEnd < range.mEnd;
                    }
                }
            }
    };

    std::vector<TimeRange> mRangeList;
    ywb_uint8_t mWeekDays;

public:
    void Copy(const ScheduleConfiguration &config)
    {
        mWeekDays = config.mWeekDays;
        mRangeList.assign(config.mRangeList.begin(), config.mRangeList.end());
    }
};
=====================
/**
 * a structure similar to ANSI struct tm with the following differences:
 *  - tm_usec isn't an ANSI field
 *  - tm_gmtoff isn't an ANSI field (it's a bsdism)
 */
struct ywb_time_exp_t {
    /** microseconds past tm_sec */
    ywb_int32_t tm_usec;
    /** (0-61) seconds past tm_min */
    ywb_int32_t tm_sec;
    /** (0-59) minutes past tm_hour */
    ywb_int32_t tm_min;
    /** (0-23) hours past midnight */
    ywb_int32_t tm_hour;
    /** (1-31) day of the month */
    ywb_int32_t tm_mday;
    /** (0-11) month of the year */
    ywb_int32_t tm_mon;
    /** year since 1900 */
    ywb_int32_t tm_year;
    /** (0-6) days since sunday */
    ywb_int32_t tm_wday;
    /** (0-365) days since jan 1 */
    ywb_int32_t tm_yday;
    /** daylight saving time */
    ywb_int32_t tm_isdst;
    /** seconds east of UTC */
    ywb_int32_t tm_gmtoff;
};

       具体分析见源码

//这是forward版本
template <class ForwardIterator, class T>
inline ForwardIterator lower_bound(ForwardIterator first, ForwardIterator last,
                                   const T& value) {
  return __lower_bound(first, last, value, distance_type(first),
                       iterator_category(first));
}

// 这是版本一的 forward_iterator 版本
template <class ForwardIterator, class T, class Distance>
ForwardIterator __lower_bound(ForwardIterator first, ForwardIterator last,
                              const T& value, Distance*,
                              forward_iterator_tag) {
  Distance len = 0;
  distance(first, last, len);	// 求取整个范围的长度,ForwardIterator没有-n操作
  Distance half;
  ForwardIterator middle;

  while (len > 0) {                        //为了跳出循环,而定义了len,如果用while(true) 然后每次判定长度在break,也行,不过没这个好
    half = len >> 1;			// 除以2,注意这种移位写法,不需编译器进行优化
    middle = first;			     // 这两行令middle 指向中间位置
    advance(middle, half);       //ForwardIterator没有+n的操作
    if (*middle < value) {		// 如果中间位置的元素值 < 标的值,value在后半区间
      first = middle;			// 这两行令 first 指向 middle 的下一位置
      ++first;
      len = len - half - 1;		// 修正 len,回头测试循环条件
    }
else						// 注意如果是相等的话,那么执行的是else语句,在前半部分找
							// 与opper_bound进行比较
      len = half;				// 修正 len,回头测试循环条件
  }
  return first;
}
// 这是带comp反函数的 forward_iterator 版本
template <class ForwardIterator, class T, class Compare, class Distance>
ForwardIterator __lower_bound(ForwardIterator first, ForwardIterator last,
                              const T& value, Compare comp, Distance*,
                              forward_iterator_tag) {
  Distance len = 0;
  distance(first, last, len);
  Distance half;
  ForwardIterator middle;

  while (len > 0) {
    half = len >> 1;
    middle = first;
    advance(middle, half);
    if (comp(*middle, value)) {
      first = middle;
      ++first;
      len = len - half - 1;
    }
    else
      len = half;
  }
  return first;
}

// 这是random_access_iterator版本
template <class ForwardIterator, class T, class Compare>
inline ForwardIterator lower_bound(ForwardIterator first, ForwardIterator last,
                                   const T& value, Compare comp) {
  return __lower_bound(first, last, value, comp, distance_type(first),
                       iterator_category(first));
}

// 这是版本一的 random_access_iterator 版本
template <class RandomAccessIterator, class T, class Distance>
RandomAccessIterator __lower_bound(RandomAccessIterator first,
                                   RandomAccessIterator last, const T& value,
                                   Distance*, random_access_iterator_tag) {
  Distance len = last - first;	//求取整个范围的长度,与ForwarIterator版本进行比较
  Distance half;
  RandomAccessIterator middle;

  while (len > 0) {
half = len >> 1;			
middle = first + half;		
    if (*middle < value) {		
      first = middle + 1;		
      len = len - half - 1;		//修正 len,回头测试循环条件,RamdonAccessIterator版本
    }
    else
      len = half;				
  }
  return first;
}



//这是带comp仿函数 random_access_iterator 版本
template <class RandomAccessIterator, class T, class Compare, class Distance>
RandomAccessIterator __lower_bound(RandomAccessIterator first,
                                   RandomAccessIterator last,
                                   const T& value, Compare comp, Distance*,
                                   random_access_iterator_tag) {
  Distance len = last - first;
  Distance half;
  RandomAccessIterator middle;

  while (len > 0) {
    half = len >> 1;
    middle = first + half;
    if (comp(*middle, value)) {
      first = middle + 1;
      len = len - half - 1;
    }
    else
      len = half;
  }
  return first;
}

// 这是forward_iterator版本
template <class ForwardIterator, class T>
inline ForwardIterator upper_bound(ForwardIterator first, ForwardIterator last,
                                   const T& value) {
  return __upper_bound(first, last, value, distance_type(first),
                       iterator_category(first));
}

// 这是版本一的 forward_iterator 版本
template <class ForwardIterator, class T, class Distance>
ForwardIterator __upper_bound(ForwardIterator first, ForwardIterator last,
                              const T& value, Distance*,
                              forward_iterator_tag) {
  Distance len = 0;
  distance(first, last, len);	
  Distance half;
  ForwardIterator middle;

  while (len > 0) {
    half = len >> 1;			
    middle = first;			    
    advance(middle, half);
    if (value < *middle)		// 如果中间位置的元素值大于标的值,证明在前半部分
      len = half;				// 修正len
else {						// 注意如果元素值相等的话,那么是在后半部分找
							// 与lower_bound进行比较
      first = middle;			// 在下半部分,令first指向middle的下一个位置
      ++first;
      len = len - half - 1;		// 修正 len
    }
  }
  return first;
}

// 这是版本一的 random_access_iterator 版本
template <class RandomAccessIterator, class T, class Distance>
RandomAccessIterator __upper_bound(RandomAccessIterator first,
                                   RandomAccessIterator last, const T& value,
                                   Distance*, random_access_iterator_tag) {
  Distance len = last - first;	
  Distance half;
  RandomAccessIterator middle;

  while (len > 0) {
    half = len >> 1;			
    middle = first + half;		
    if (value < *middle)		
      len = half;				    
	 else {
      first = middle + 1;		
      len = len - half - 1;		
    }
  }
  return first;
}

// 这是带comp的版本
template <class ForwardIterator, class T, class Compare>
inline ForwardIterator upper_bound(ForwardIterator first, ForwardIterator last,
                                   const T& value, Compare comp) {
  return __upper_bound(first, last, value, comp, distance_type(first),
                       iterator_category(first));
}

// 这是带comp的 forward_iterator 版本
template <class ForwardIterator, class T, class Compare, class Distance>
ForwardIterator __upper_bound(ForwardIterator first, ForwardIterator last,
                              const T& value, Compare comp, Distance*,
                              forward_iterator_tag) {
  Distance len = 0;
  distance(first, last, len);
  Distance half;
  ForwardIterator middle;

  while (len > 0) {
    half = len >> 1;
    middle = first;
    advance(middle, half);
    if (comp(value, *middle))
      len = half;
    else {
      first = middle;
      ++first;
      len = len - half - 1;
    }
  }
  return first;
}

// 这是带comp的 random_access_iterator 版本
template <class RandomAccessIterator, class T, class Compare, class Distance>
RandomAccessIterator __upper_bound(RandomAccessIterator first,
                                   RandomAccessIterator last,
                                   const T& value, Compare comp, Distance*,
                                   random_access_iterator_tag) {
  Distance len = last - first;
  Distance half;
  RandomAccessIterator middle;

  while (len > 0) {
    half = len >> 1;
    middle = first + half;
    if (comp(value, *middle))
      len = half;
    else {
      first = middle + 1;
      len = len - half - 1;
    }
  }
  return first;
}

// 版本一
template <class ForwardIterator, class T>
bool binary_search(ForwardIterator first, ForwardIterator last,
                   const T& value) {
  ForwardIterator i = lower_bound(first, last, value);  
//这里的实现就是调用的lower_bound ,并且如果元素不存在那么lower_bound指向的元素一定是
//operator < 为ture的地方。
  return i != last && !(value < *i);
}

// 版本二
template <class ForwardIterator, class T, class Compare>
bool binary_search(ForwardIterator first, ForwardIterator last, const T& value,
                   Compare comp) {
  ForwardIterator i = lower_bound(first, last, value, comp);
  return i != last && !comp(value, *i);
}


binary_search二分法怎样使用?

二分法检索又称折半检索,二分法检索的基本思想是设字典中的元素从小到大有序地存放在数组中,首先将给定值key与字典中间位置上元素的关键码比较,如果相等,则检索成功;否则,若key小,则在字典前半部分中继续进行二分法检索,若key大,则在字典后半部分中继续进行二分法检索。这样,经过一次比较就缩小一半的检索区间,如此进行下去,直到检索成功或检索失败。二分法检索是一种效率较高的检索方法,要求字典在顺序表中按关键码排序。

binary_search

原型:

 #include <algorithm>
 bool binary_search( forward_iterator start, forward_iterator end, const TYPE& val );
 bool binary_search( forward_iterator start, forward_iterator end, const TYPE& val, Comp f );

返回值:

true if an element is found in the range that is equal or equivalent to the specified value; otherwise, false.

代码演示:

#include <algorithm>

int main()
{
    int nums[] = { -242, -1, 0, 5, 8, 9, 11 };//必须按递增顺序排列
    int start = 0; int end = 7;  
    for( int i = 0; i < 10; i++ ) 
    {
        if( std::binary_search( nums+start, nums+end, i ) )//如果找到返回TRUE,没有找到则返回FALSE
        {
            printf("找到\n");
        }
        else 
        {
            printf("没找到\n");
        }
    }
    return 0;
}

附注1:数组必须是按递增顺序排列的,否则错误

更详细的可参考MSDN,以及上面所列举的一个例子


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值