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和手寫快排的運行效率哪個比較高

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