STL源码剖析——STL算法之merge合并算法

前言

由于在前文的《STL算法剖析》中,源码剖析非常多,不方便学习,也不方便以后复习,这里把这些算法进行归类,对他们单独的源码剖析进行讲解。本文介绍的STL算法中的merge合并算法。源码中介绍了函数merge、inplace_merge。并对这些函数的源码进行详细的剖析,并适当给出使用例子,具体详见下面源码剖析。

merge合并算法源码剖析

// merge, with and without an explicitly supplied comparison function.
//将两个已排序的区间[first1,last1)和区间[first2,last2)合并
/*
函数功能:Combines the elements in the sorted ranges [first1,last1) and [first2,last2),
into a new range beginning at result with all its elements sorted.

函数原型:
default (1)	:版本一
	template <class InputIterator1, class InputIterator2, class OutputIterator>
	OutputIterator merge (InputIterator1 first1, InputIterator1 last1,
                        InputIterator2 first2, InputIterator2 last2,
                        OutputIterator result);
custom (2)	:版本二
	template <class InputIterator1, class InputIterator2,
          class OutputIterator, class Compare>
	OutputIterator merge (InputIterator1 first1, InputIterator1 last1,
                        InputIterator2 first2, InputIterator2 last2,
                        OutputIterator result, Compare comp);
*/
//版本一:
template <class _InputIter1, class _InputIter2, class _OutputIter>
_OutputIter merge(_InputIter1 __first1, _InputIter1 __last1,
                  _InputIter2 __first2, _InputIter2 __last2,
                  _OutputIter __result) {
  __STL_REQUIRES(_InputIter1, _InputIterator);
  __STL_REQUIRES(_InputIter2, _InputIterator);
  __STL_REQUIRES(_OutputIter, _OutputIterator);
  __STL_REQUIRES_SAME_TYPE(
          typename iterator_traits<_InputIter1>::value_type,
          typename iterator_traits<_InputIter2>::value_type);
  __STL_REQUIRES(typename iterator_traits<_InputIter1>::value_type,
                 _LessThanComparable);
  //两个序列都尚未到达尾端,则执行while循环
  /*
  情况1:若序列二元素较小,则记录到目标区,且移动序列二的迭代器,但是序列一的迭代器不变.
  情况2:若序列一元素较小或相等,则记录到目标区,且移动序列一的迭代器,但是序列二的迭代器不变.
  最后:把剩余元素的序列复制到目标区
  */
  while (__first1 != __last1 && __first2 != __last2) {
	  //情况1
    if (*__first2 < *__first1) {//若序列二元素较小
      *__result = *__first2;//将元素记录到目标区
      ++__first2;//移动迭代器
    }
	//情况2
    else {//若序列一元素较小或相等
      *__result = *__first1;//将元素记录到目标区
      ++__first1;//移动迭代器
    }
    ++__result;//更新目标区位置,以便下次记录数据
  }
  //若有序列到达尾端,则把没到达尾端的序列剩余元素复制到目标区
  //此时,区间[first1,last1)和区间[first2,last2)至少一个必定为空
  return copy(__first2, __last2, copy(__first1, __last1, __result));
}
//版本二
template <class _InputIter1, class _InputIter2, class _OutputIter,
          class _Compare>
_OutputIter merge(_InputIter1 __first1, _InputIter1 __last1,
                  _InputIter2 __first2, _InputIter2 __last2,
                  _OutputIter __result, _Compare __comp) {
  __STL_REQUIRES(_InputIter1, _InputIterator);
  __STL_REQUIRES(_InputIter2, _InputIterator);
  __STL_REQUIRES_SAME_TYPE(
          typename iterator_traits<_InputIter1>::value_type,
          typename iterator_traits<_InputIter2>::value_type);
  __STL_REQUIRES(_OutputIter, _OutputIterator);
  __STL_BINARY_FUNCTION_CHECK(_Compare, bool,
          typename iterator_traits<_InputIter1>::value_type,
          typename iterator_traits<_InputIter1>::value_type);
  while (__first1 != __last1 && __first2 != __last2) {
    if (__comp(*__first2, *__first1)) {
      *__result = *__first2;
      ++__first2;
    }
    else {
      *__result = *__first1;
      ++__first1;
    }
    ++__result;
  }
  return copy(__first2, __last2, copy(__first1, __last1, __result));
}
//merge函数举例:
/*
	#include <iostream>     // std::cout
	#include <algorithm>    // std::merge, std::sort
	#include <vector>       // std::vector

	int main () {
	  int first[] = {5,10,15,20,25};
	  int second[] = {50,40,30,20,10};
	  std::vector<int> v(10);

	  std::sort (first,first+5);
	  std::sort (second,second+5);
	  std::merge (first,first+5,second,second+5,v.begin());

	  std::cout << "The resulting vector contains:";
	  for (std::vector<int>::iterator it=v.begin(); it!=v.end(); ++it)
		std::cout << ' ' << *it;
	  std::cout << '\n';

	  return 0;
	}
	Output:
	The resulting vector contains: 5 10 10 15 20 20 25 30 40 50
*/

// inplace_merge and its auxiliary functions.
//版本一的辅助函数,无缓冲区的操作
template <class _BidirectionalIter, class _Distance>
void __merge_without_buffer(_BidirectionalIter __first,
                            _BidirectionalIter __middle,
                            _BidirectionalIter __last,
                            _Distance __len1, _Distance __len2) {
  if (__len1 == 0 || __len2 == 0)
    return;
  if (__len1 + __len2 == 2) {
    if (*__middle < *__first)
      iter_swap(__first, __middle);
    return;
  }
  _BidirectionalIter __first_cut = __first;
  _BidirectionalIter __second_cut = __middle;
  _Distance __len11 = 0;
  _Distance __len22 = 0;
  if (__len1 > __len2) {
    __len11 = __len1 / 2;
    advance(__first_cut, __len11);
    __second_cut = lower_bound(__middle, __last, *__first_cut);
    distance(__middle, __second_cut, __len22);
  }
  else {
    __len22 = __len2 / 2;
    advance(__second_cut, __len22);
    __first_cut = upper_bound(__first, __middle, *__second_cut);
    distance(__first, __first_cut, __len11);
  }
  _BidirectionalIter __new_middle
    = rotate(__first_cut, __middle, __second_cut);
  __merge_without_buffer(__first, __first_cut, __new_middle,
                         __len11, __len22);
  __merge_without_buffer(__new_middle, __second_cut, __last, __len1 - __len11,
                         __len2 - __len22);
}

template <class _BidirectionalIter, class _Distance, class _Compare>
void __merge_without_buffer(_BidirectionalIter __first,
                            _BidirectionalIter __middle,
                            _BidirectionalIter __last,
                            _Distance __len1, _Distance __len2,
                            _Compare __comp) {
  if (__len1 == 0 || __len2 == 0)
    return;
  if (__len1 + __len2 == 2) {
    if (__comp(*__middle, *__first))
      iter_swap(__first, __middle);
    return;
  }
  _BidirectionalIter __first_cut = __first;
  _BidirectionalIter __second_cut = __middle;
  _Distance __len11 = 0;
  _Distance __len22 = 0;
  if (__len1 > __len2) {
    __len11 = __len1 / 2;
    advance(__first_cut, __len11);
    __second_cut = lower_bound(__middle, __last, *__first_cut, __comp);
    distance(__middle, __second_cut, __len22);
  }
  else {
    __len22 = __len2 / 2;
    advance(__second_cut, __len22);
    __first_cut = upper_bound(__first, __middle, *__second_cut, __comp);
    distance(__first, __first_cut, __len11);
  }
  _BidirectionalIter __new_middle
    = rotate(__first_cut, __middle, __second_cut);
  __merge_without_buffer(__first, __first_cut, __new_middle, __len11, __len22,
                         __comp);
  __merge_without_buffer(__new_middle, __second_cut, __last, __len1 - __len11,
                         __len2 - __len22, __comp);
}
//版本一的辅助函数,有缓冲区的操作
template <class _BidirectionalIter1, class _BidirectionalIter2,
          class _Distance>
_BidirectionalIter1 __rotate_adaptive(_BidirectionalIter1 __first,
                                      _BidirectionalIter1 __middle,
                                      _BidirectionalIter1 __last,
                                      _Distance __len1, _Distance __len2,
                                      _BidirectionalIter2 __buffer,
                                      _Distance __buffer_size) {
  _BidirectionalIter2 __buffer_end;
  if (__len1 > __len2 && __len2 <= __buffer_size) {//缓冲区足够放置序列二
    __buffer_end = copy(__middle, __last, __buffer);
    copy_backward(__first, __middle, __last);
    return copy(__buffer, __buffer_end, __first);
  }
  else if (__len1 <= __buffer_size) {//缓冲区足够放置序列一
    __buffer_end = copy(__first, __middle, __buffer);
    copy(__middle, __last, __first);
    return copy_backward(__buffer, __buffer_end, __last);
  }
  else//若缓冲区仍然不够,则调用STL算法rotate,不使用缓冲区
    return rotate(__first, __middle, __last);
}

template <class _BidirectionalIter1, class _BidirectionalIter2,
          class _BidirectionalIter3>
_BidirectionalIter3 __merge_backward(_BidirectionalIter1 __first1,
                                     _BidirectionalIter1 __last1,
                                     _BidirectionalIter2 __first2,
                                     _BidirectionalIter2 __last2,
                                     _BidirectionalIter3 __result) {
  if (__first1 == __last1)
    return copy_backward(__first2, __last2, __result);
  if (__first2 == __last2)
    return copy_backward(__first1, __last1, __result);
  --__last1;
  --__last2;
  while (true) {
    if (*__last2 < *__last1) {
      *--__result = *__last1;
      if (__first1 == __last1)
        return copy_backward(__first2, ++__last2, __result);
      --__last1;
    }
    else {
      *--__result = *__last2;
      if (__first2 == __last2)
        return copy_backward(__first1, ++__last1, __result);
      --__last2;
    }
  }
}

template <class _BidirectionalIter1, class _BidirectionalIter2,
          class _BidirectionalIter3, class _Compare>
_BidirectionalIter3 __merge_backward(_BidirectionalIter1 __first1,
                                     _BidirectionalIter1 __last1,
                                     _BidirectionalIter2 __first2,
                                     _BidirectionalIter2 __last2,
                                     _BidirectionalIter3 __result,
                                     _Compare __comp) {
  if (__first1 == __last1)
    return copy_backward(__first2, __last2, __result);
  if (__first2 == __last2)
    return copy_backward(__first1, __last1, __result);
  --__last1;
  --__last2;
  while (true) {
    if (__comp(*__last2, *__last1)) {
      *--__result = *__last1;
      if (__first1 == __last1)
        return copy_backward(__first2, ++__last2, __result);
      --__last1;
    }
    else {
      *--__result = *__last2;
      if (__first2 == __last2)
        return copy_backward(__first1, ++__last1, __result);
      --__last2;
    }
  }
}
//版本一的辅助函数,有缓冲区的操作
template <class _BidirectionalIter, class _Distance, class _Pointer>
void __merge_adaptive(_BidirectionalIter __first,
                      _BidirectionalIter __middle,
                      _BidirectionalIter __last,
                      _Distance __len1, _Distance __len2,
                      _Pointer __buffer, _Distance __buffer_size) {
  if (__len1 <= __len2 && __len1 <= __buffer_size) {
	  //case1:把序列一放在缓冲区
    _Pointer __buffer_end = copy(__first, __middle, __buffer);
	//直接调用归并函数merge
    merge(__buffer, __buffer_end, __middle, __last, __first);
  }
  else if (__len2 <= __buffer_size) {
	  //case2:把序列二放在缓冲区
    _Pointer __buffer_end = copy(__middle, __last, __buffer);
    __merge_backward(__first, __middle, __buffer, __buffer_end, __last);
  }
  else {//case3:缓冲区不足放置任何一个序列
    _BidirectionalIter __first_cut = __first;
    _BidirectionalIter __second_cut = __middle;
    _Distance __len11 = 0;
    _Distance __len22 = 0;
    if (__len1 > __len2) {//若序列一比较长
      __len11 = __len1 / 2;//计算序列一的一半
      advance(__first_cut, __len11);//让first_cut指向序列一的中间位置
	  //找出*__first_cut在[middle,last)区间中的第一个不小于*__first_cut的元素位置
      __second_cut = lower_bound(__middle, __last, *__first_cut);
	  //计算middle到__second_cut之间的距离,保存在__len22
      distance(__middle, __second_cut, __len22);
    }
    else {//若序列二比较长
      __len22 = __len2 / 2;//计算序列二的一半
      advance(__second_cut, __len22);//让__second_cut指向序列二的中间位置
	  //找出*__second_cut在[first,middle)区间中的第一个大于*__second_cut的元素位置
      __first_cut = upper_bound(__first, __middle, *__second_cut);
	  //计算__first到__first_cut之间的距离,保存在__len11
      distance(__first, __first_cut, __len11);
    }
    _BidirectionalIter __new_middle =
      __rotate_adaptive(__first_cut, __middle, __second_cut, __len1 - __len11,
                        __len22, __buffer, __buffer_size);
	//对左半段递归调用
    __merge_adaptive(__first, __first_cut, __new_middle, __len11,
                     __len22, __buffer, __buffer_size);
	//对右半段递归调用
    __merge_adaptive(__new_middle, __second_cut, __last, __len1 - __len11,
                     __len2 - __len22, __buffer, __buffer_size);
  }
}

template <class _BidirectionalIter, class _Distance, class _Pointer,
          class _Compare>
void __merge_adaptive(_BidirectionalIter __first,
                      _BidirectionalIter __middle,
                      _BidirectionalIter __last,
                      _Distance __len1, _Distance __len2,
                      _Pointer __buffer, _Distance __buffer_size,
                      _Compare __comp) {
  if (__len1 <= __len2 && __len1 <= __buffer_size) {
    _Pointer __buffer_end = copy(__first, __middle, __buffer);
    merge(__buffer, __buffer_end, __middle, __last, __first, __comp);
  }
  else if (__len2 <= __buffer_size) {
    _Pointer __buffer_end = copy(__middle, __last, __buffer);
    __merge_backward(__first, __middle, __buffer, __buffer_end, __last,
                     __comp);
  }
  else {
    _BidirectionalIter __first_cut = __first;
    _BidirectionalIter __second_cut = __middle;
    _Distance __len11 = 0;
    _Distance __len22 = 0;
    if (__len1 > __len2) {
      __len11 = __len1 / 2;
      advance(__first_cut, __len11);
      __second_cut = lower_bound(__middle, __last, *__first_cut, __comp);
      distance(__middle, __second_cut, __len22);
    }
    else {
      __len22 = __len2 / 2;
      advance(__second_cut, __len22);
      __first_cut = upper_bound(__first, __middle, *__second_cut, __comp);
      distance(__first, __first_cut, __len11);
    }
    _BidirectionalIter __new_middle =
      __rotate_adaptive(__first_cut, __middle, __second_cut, __len1 - __len11,
                        __len22, __buffer, __buffer_size);
    __merge_adaptive(__first, __first_cut, __new_middle, __len11,
                     __len22, __buffer, __buffer_size, __comp);
    __merge_adaptive(__new_middle, __second_cut, __last, __len1 - __len11,
                     __len2 - __len22, __buffer, __buffer_size, __comp);
  }
}
//版本一的辅助函数
template <class _BidirectionalIter, class _Tp, class _Distance>
inline void __inplace_merge_aux(_BidirectionalIter __first,
                                _BidirectionalIter __middle,
                                _BidirectionalIter __last, _Tp*, _Distance*) {
  _Distance __len1 = 0;
  distance(__first, __middle, __len1);//计算序列一的长度
  _Distance __len2 = 0;
  distance(__middle, __last, __len2);//计算序列二的长度

  //使用暂时缓冲区
  _Temporary_buffer<_BidirectionalIter, _Tp> __buf(__first, __last);
  if (__buf.begin() == 0)//若缓冲区配置失败
	  //则调用不使用缓冲区的合并操作
    __merge_without_buffer(__first, __middle, __last, __len1, __len2);
  else//若分配成功
	  //则调用具有缓冲区的合并操作
    __merge_adaptive(__first, __middle, __last, __len1, __len2,
                     __buf.begin(), _Distance(__buf.size()));
}

template <class _BidirectionalIter, class _Tp,
          class _Distance, class _Compare>
inline void __inplace_merge_aux(_BidirectionalIter __first,
                                _BidirectionalIter __middle,
                                _BidirectionalIter __last, _Tp*, _Distance*,
                                _Compare __comp) {
  _Distance __len1 = 0;
  distance(__first, __middle, __len1);
  _Distance __len2 = 0;
  distance(__middle, __last, __len2);

  _Temporary_buffer<_BidirectionalIter, _Tp> __buf(__first, __last);
  if (__buf.begin() == 0)
    __merge_without_buffer(__first, __middle, __last, __len1, __len2, __comp);
  else
    __merge_adaptive(__first, __middle, __last, __len1, __len2,
                     __buf.begin(), _Distance(__buf.size()),
                     __comp);
}
//将两个已排序的序列[first,middle)和[middle,last)合并成单一有序序列.
//若原来是增序,现在也是递增排序,若原来是递减排序,现在也是递减排序
/*
函数功能:Merges two consecutive sorted ranges: [first,middle) and [middle,last),
putting the result into the combined sorted range [first,last).
函数原型:
default (1)	:版本一
	template <class BidirectionalIterator>
	void inplace_merge (BidirectionalIterator first, BidirectionalIterator middle,
                      BidirectionalIterator last);
custom (2)	:版本二
	template <class BidirectionalIterator, class Compare>
	void inplace_merge (BidirectionalIterator first, BidirectionalIterator middle,
                      BidirectionalIterator last, Compare comp);
*/
//版本一
template <class _BidirectionalIter>
inline void inplace_merge(_BidirectionalIter __first,
                          _BidirectionalIter __middle,
                          _BidirectionalIter __last) {
  __STL_REQUIRES(_BidirectionalIter, _Mutable_BidirectionalIterator);
  __STL_REQUIRES(typename iterator_traits<_BidirectionalIter>::value_type,
                 _LessThanComparable);
  if (__first == __middle || __middle == __last)//若有空序列,则之间返回
    return;
  __inplace_merge_aux(__first, __middle, __last,
                      __VALUE_TYPE(__first), __DISTANCE_TYPE(__first));
}
//版本二
template <class _BidirectionalIter, class _Compare>
inline void inplace_merge(_BidirectionalIter __first,
                          _BidirectionalIter __middle,
                          _BidirectionalIter __last, _Compare __comp) {
  __STL_REQUIRES(_BidirectionalIter, _Mutable_BidirectionalIterator);
  __STL_BINARY_FUNCTION_CHECK(_Compare, bool,
           typename iterator_traits<_BidirectionalIter>::value_type,
           typename iterator_traits<_BidirectionalIter>::value_type);
  if (__first == __middle || __middle == __last)
    return;
  __inplace_merge_aux(__first, __middle, __last,
                      __VALUE_TYPE(__first), __DISTANCE_TYPE(__first),
                      __comp);
}
//inplace_merge函数举例:
/*
	#include <iostream>     // std::cout
	#include <algorithm>    // std::inplace_merge, std::sort, std::copy
	#include <vector>       // std::vector

	int main () {
	  int first[] = {5,10,15,20,25};
	  int second[] = {50,40,30,20,10};
	  std::vector<int> v(10);
	  std::vector<int>::iterator it;

	  std::sort (first,first+5);
	  std::sort (second,second+5);

	  it=std::copy (first, first+5, v.begin());
		 std::copy (second,second+5,it);

	  std::inplace_merge (v.begin(),v.begin()+5,v.end());

	  std::cout << "The resulting vector contains:";
	  for (it=v.begin(); it!=v.end(); ++it)
		std::cout << ' ' << *it;
	  std::cout << '\n';

	  return 0;
	}
	Output:
	The resulting vector contains: 5 10 10 15 20 20 25 30 40 50
*/

参考资料:

《STL源码剖析》侯捷

时间: 2024-10-26 02:40:32

STL源码剖析——STL算法之merge合并算法的相关文章

STL源码剖析——STL算法stl_algo.h

前言 在前面的博文中剖析了STL的数值算法.基本算法和set集合算法,本文剖析STL其他的算法,例如排序算法.合并算法.查找算法等等.在剖析的时候,会针对函数给出一些例子说明函数的使用.源码出自SGI STL中的<stl_algo.h>文件.注:本文的源码非常多,可能后续博文会对这些算法进行归类分析. STL算法剖析 #ifndef __SGI_STL_INTERNAL_ALGO_H #define __SGI_STL_INTERNAL_ALGO_H #include <stl_heap

STL源码剖析——STL算法之find查找算法

前言 由于在前文的<STL算法剖析>中,源码剖析非常多,不方便学习,也不方便以后复习,这里把这些算法进行归类,对他们单独的源码剖析进行讲解.本文介绍的STL算法中的find.search查找算法.在STL源码中有关算法的函数大部分在本文介绍,包含findand find_if.adjacent_find.search.search_n.lower_bound. upper_bound. equal_range.binary_search.find_first_of.find_end相关算法,下

STL源码剖析——STL算法之remove删除算法

前言 由于在前文的<STL算法剖析>中,源码剖析非常多,不方便学习,也不方便以后复习,这里把这些算法进行归类,对他们单独的源码剖析进行讲解.本文介绍的STL算法中的remove删除算法,源码中介绍了函数remove.remove_copy.remove_if.remove_copy_if.unique.unique_copy.并对这些函数的源码进行详细的剖析,并适当给出使用例子,具体详见下面源码剖析. remove移除算法源码剖析 // remove, remove_if, remove_co

STL源码剖析——STL函数对象

前言 在STL中,函数对象也是比较重要的,有时候可以限定STL算法的行为,例如在前面介绍的<STL算法剖析>中,每个算法基本上都提供了两个操作版本,其中就用一个版本允许用户指定函数对象,这样可以根据用户的需要对算法进行操作.函数对象是一种具有函数特质的对象,所以可以作为算法的参数.本文介绍的函数对象比较简单,是基于一元或者二元操作结构的算术类函数对象.关系运算类函数对象.逻辑运算类函数对象.在定义函数对象时,为了使其具有函数行为,则必须重载operator()操作符.本文源码出自SGI STL

STL源码剖析——STL算法之sort排序算法

前言 由于在前文的<STL算法剖析>中,源码剖析非常多,不方便学习,也不方便以后复习,这里把这些算法进行归类,对他们单独的源码剖析进行讲解.本文介绍的STL算法中的sort排序算法,SGI STL中的排序算法不是简单的快速排序,而是交叉利用各种排序:堆排序.插入排序和快速排序:这样做的目的是提高效率,针对数据量比较大的采用快速排序,数据量比较小的可以采用堆排序或插入排序.注意:STL的sort排序算法的迭代器必须是随机访问迭代器. sort排序算法剖析 // Return a random n

STL 源码剖析 算法 stl_algo.h -- merge sort

本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie merge sort ---------------------------------------------------------------------- 描述:归并排序 思路: 1.将区间对半分割 2.对左.右段分别排序 3.利用inplace_merge将左.右段合并成为一个完整的有序序列 复杂度:O(nlog n) 源码: template<class Bidirection

STL 源码剖析 算法 stl_algo.h -- merge

本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie merge (应用于有序区间) -------------------------------------------------------------------------- 描述:将两个经过排序的集合S1和S2,合并起来置于另一段空间.所得结果也是一个有序(sorted)序列 思路: 1.遍历两个序列直到其中一个结束了 2.如果序列一的元素较小,将它放到结果序列中,并前进 1 3.

STL 源码剖析 算法 stl_algo.h -- inplace_merge

本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie inplace_merge(应用于有序区间) -------------------------------------------------------------------- 描述:如果两个连接在一起的序列[first, middle)和 [middle, last]都已排序, 那么 inplace_merge 可将它们结合成单一一个序列,并仍有序. 源码: template <c

STL 源码剖析 算法 stl_algo.h -- search_n

本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie search_n ---------------------------------------------------------------------------------------- 描述:在序列[first, last) 所涵盖的区间中,查找"连续 count 个符合条件之元素"所形成的子序列, 并返回迭代器 last 思路: 1.首先找出 value 第一次出现点