STL源码分析之二分查找算法

前言

前面我们分析了关于stl_algo.h中的基本算法, 本节也将继续分析该文件中的算法实现, 即二分查找.

stl_algo.h提供了lower_boundupper_bound两种查找, 前者是找出第一个满足条件的迭代器, 后者则是找出最后一个满足条件的迭代器, 两者结合就能知道该容器中重复的个数.

二分查找分析

lower_bound

ForwardIterator版本

// 版本一
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));
}

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);
  Distance half;
  ForwardIterator middle;

  while (len > 0) {
    half = len >> 1;	// 相当于除2
      // middle为区间的起始位置
    middle = first;
      // 设置middle为区间的中间值
    advance(middle, half);
      // 将value值与中间值比较, 即是二分查找, 若中间值小于value, 则继续查找右半部分
    if (*middle < value) {
      first = middle;
      ++first;
      len = len - half - 1;
    }
    else
      len = half;
  }
  return first;
}

// 版本二
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));
}

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;
      // 设置middle为区间的中间值
    advance(middle, half);
      // 满足的条件的进行比赛
    if (comp(*middle, value)) {
      first = middle;
      ++first;
      len = len - half - 1;
    }
    else
      len = half;
  }
  return first;
}

RandomAccessIterator 版本

// 版本一
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;
  Distance half;
  RandomAccessIterator middle;
	// 二分法
  while (len > 0) {
    half = len >> 1;	// 相当于除2
      // 设置middle为区间的中间值. 
      // 这里直接求出middle的值, 更加的快速
    middle = first + half;
    if (*middle < value) {
      first = middle + 1;
      len = len - half - 1;
    }
    else
      len = half;
  }
  return first;
}
// 版本二
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为区间的中间值. 
      // 这里直接求出middle的值, 更加的快速
    middle = first + half;
    if (comp(*middle, value)) {
      first = middle + 1;
      len = len - half - 1;
    }
    else
      len = half;
  }
  return first;
}
upper_bound

这里就只分析ForwardIterator就行了, RandomAccessIterator也跟上面一样的操作

// 版本一
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));
}

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;	// 相当于除2
      // middle为区间的起始位置
    middle = first;
      // 设置middle为区间的中间值
    advance(middle, half);
      // 将value值与中间值比较, 即是二分查找, 若中间值小于value, 则继续查找右半部分
    if (comp(value, *middle))
      len = half;
    else {
      first = middle;
      ++first;
      len = len - half - 1;
    }
  }
  return first;
}
// 版本二
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));
}

总结

关于STL的二分查找让我学习到以前自己实现的有很多的问题, 没有这样的区分重复的数据, 而是直接找到就返回, 而STL对其有两种不同的选择, 可以找到第一出现, 也可以找到最后一次出现, 学习STL总能让人不禁易认识很多东西, 学到很多细节的处理与完善. 关于stl_algo.h中的排序我暂时不再继续分析了, 等之后有时间再来重新总结.

知乎有对STL泛型算法中sort的效率的讨论stl的sort和手写快排的运行效率哪个比较高

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值