STL 的算法(algo) 分析(六)

#-algo #-STL

__partial_sort 实现部分排序,令 __first 到 __middle 的距离为 __len。函数对 __first 到 __last 中最小的 __len 个元素进行排序,并将前 __len 个最小元素排序后的序列放置到 __first 到 __middle 之间的位置。

函数首先对 __first 到 __middle 中的元素构造一个最大堆,for 循环中将最小的 __len 个元素移动到 __first 到 __middle 之间 (在堆中)。将余下的元素移动到 __middle 到 __last 之间。__pop_heap 函数每次将 first 所处的位置的元素(堆中的最大元素)弹出放置到 __i 所在的位置,并将原先 __i 所在的位置的元素插入到堆中,堆中的元素个数保持不变。最后调用 sort_heap 对最小的 __len 个元素进行排序。

template <class _RandomAccessIter, class _Tp>
void __partial_sort(_RandomAccessIter __first, _RandomAccessIter __middle,
		    _RandomAccessIter __last, _Tp*) {
  make_heap(__first, __middle);
  for (_RandomAccessIter __i = __middle; __i < __last; ++__i)
    if (*__i < *__first) 
      __pop_heap(__first, __middle, __i, _Tp(*__i),
		 __DISTANCE_TYPE(__first));
  sort_heap(__first, __middle);
}

partial_sort 对 __first 到 __last 中的元素进行部分排序,通过调用上面定义的 __partial_sort 进行排序。

template <class _RandomAccessIter>
inline void partial_sort(_RandomAccessIter __first,
			 _RandomAccessIter __middle,
			 _RandomAccessIter __last) {
  __STL_REQUIRES(_RandomAccessIter, _Mutable_RandomAccessIterator);
  __STL_REQUIRES(typename iterator_traits<_RandomAccessIter>::value_type,
		 _LessThanComparable);
  __partial_sort(__first, __middle, __last, __VALUE_TYPE(__first));
}

函数 __partial_sort_copy 将 __first 到 __last 中部分排序的内容复制到 __result_first 到 __result_last 之间。令 __first 到 __last 的长度为 __l1,令 __result_first 到 __result_last 的元素个数为 __l2。函数最终会将 __first 到 __last 中 min(__l1, __l2) 个最小元素排好序后复制到 __result_first 到 __result_last 之间。

如果 __l1 < __l2 函数先将 __first 到 __last 的所有元素复制到 __result_first 到 __result_last 之间。否则将 __first 到 __last 的最小的 __l2 个元素复制到 __result_first 到 __result_last 之间。

在 __result_first 到 __result_real_last 之间的元素构造一个最大堆。如果 __first 不等于结束标记 __last ,while 循环中不断的将不属于 __first 到 __last 中 min(__l1, __l2) 个最小元素的元素移出最大堆,并将属于的元素替换进来。退出循环后,__result_first 到 __result_real_last 之间的元素是 __first 到 __last 中 min(__l1, __l2) 个最小元素。最后调用 sort_heap 对 __result_first 到 __result_real_last 之间的元素进行排序。

template <class _InputIter, class _RandomAccessIter, class _Distance,
	  class _Tp>
_RandomAccessIter __partial_sort_copy(_InputIter __first,
				      _InputIter __last,
				      _RandomAccessIter __result_first,
				      _RandomAccessIter __result_last, 
				      _Distance*, _Tp*) {
  if (__result_first == __result_last) return __result_last;
  _RandomAccessIter __result_real_last = __result_first;
  while(__first != __last && __result_real_last != __result_last) {
    *__result_real_last = *__first;
    ++__result_real_last;
    ++__first;
  }
  make_heap(__result_first, __result_real_last);
  while (__first != __last) {
    if (*__first < *__result_first) 
      __adjust_heap(__result_first, _Distance(0),
		    _Distance(__result_real_last - __result_first),
		    _Tp(*__first));
    ++__first;
  }
  sort_heap(__result_first, __result_real_last);
  return __result_real_last;
}

函数 partial_sort_copy 将 __first 到 __last 中部分排序的内容复制到 __result_first 到 __result_last 之间。

template <class _InputIter, class _RandomAccessIter>
inline _RandomAccessIter
partial_sort_copy(_InputIter __first, _InputIter __last,
		  _RandomAccessIter __result_first,
		  _RandomAccessIter __result_last) {
  __STL_REQUIRES(_InputIter, _InputIterator);
  __STL_REQUIRES(_RandomAccessIter, _Mutable_RandomAccessIterator);
  __STL_CONVERTIBLE(typename iterator_traits<_InputIter>::value_type,
		    typename iterator_traits<_RandomAccessIter>::value_type);
  __STL_REQUIRES(typename iterator_traits<_RandomAccessIter>::value_type,
		 _LessThanComparable);
  __STL_REQUIRES(typename iterator_traits<_InputIter>::value_type,
		 _LessThanComparable);
  return __partial_sort_copy(__first, __last, __result_first, __result_last, 
			     __DISTANCE_TYPE(__result_first),
			     __VALUE_TYPE(__first));
}

函数 __nth_element 用来确定如果对 __first 到 __last 之间的元素进行排序,那么 __nth 位置(注意这里 __nth 是一个实际地址,而不是一个像序号一样的索引地址) 所在的元素。函数调用之前定义的 __unguarded_partition 将 __first 到 __last 之间的内容分割为两部分,使得第一部分的元素都小于第二部分的元素。二者的分割值为 __cut。

然后根据 __cut 和 __nth 的位置更新 __first 和 __last 的值,以保证 __cut 位置所在的元素始终包含在 __first 和 __last 之间。当 __first 和 __last 之间的差值小于 3 时,直接应用插入排序对 __first 到 __last 之间的元素进行排序,此时 __nth 位置的元素即为所求。

template <class _RandomAccessIter, class _Tp>
void __nth_element(_RandomAccessIter __first, _RandomAccessIter __nth,
		   _RandomAccessIter __last, _Tp*) {
  while (__last - __first > 3) {
    _RandomAccessIter __cut =
      __unguarded_partition(__first, __last,
			    _Tp(__median(*__first,
					 *(__first + (__last - __first)/2),
					 *(__last - 1))));
    if (__cut <= __nth)
      __first = __cut;
    else 
      __last = __cut;
  }
  __insertion_sort(__first, __last);
}

函数 __nth_element 求如果将 __first 到 __last 之间的元素进行排序,位置 __nth 上所在的元素。

template <class _RandomAccessIter>
inline void nth_element(_RandomAccessIter __first, _RandomAccessIter __nth,
			_RandomAccessIter __last) {
  __STL_REQUIRES(_RandomAccessIter, _Mutable_RandomAccessIterator);
  __STL_REQUIRES(typename iterator_traits<_RandomAccessIter>::value_type,
		 _LessThanComparable);
  __nth_element(__first, __nth, __last, __VALUE_TYPE(__first));
}

函数 __lower_bound 求 __first 到 __last 之间的有序序列中从 __first 开始第一个第一个大于或者等于给定值 __val 的位置。如果大于等于 __val 的值存在,则返回从 __first 开始第一个大于等于 __val 的元素的位置。否则返回值为 __last 。

template <class _ForwardIter, class _Tp, class _Distance>
_ForwardIter __lower_bound(_ForwardIter __first, _ForwardIter __last,
			   const _Tp& __val, _Distance*) 
{
  _Distance __len = 0;
  distance(__first, __last, __len);
  _Distance __half;
  _ForwardIter __middle;

  while (__len > 0) {
    __half = __len >> 1;
    __middle = __first;
    advance(__middle, __half);
    if (*__middle < __val) {
      __first = __middle;
      ++__first;
      __len = __len - __half - 1;
    }
    else
      __len = __half;
  }
  return __first;
}

函数 lower_bound 返回从 __first 开始第一个大于或者等于 __val 的元素的位置。函数调用 __lower_bound 来实现。

template <class _ForwardIter, class _Tp>
inline _ForwardIter lower_bound(_ForwardIter __first, _ForwardIter __last,
				const _Tp& __val) {
  __STL_REQUIRES(_ForwardIter, _ForwardIterator);
  __STL_REQUIRES_SAME_TYPE(_Tp,
      typename iterator_traits<_ForwardIter>::value_type);
  __STL_REQUIRES(_Tp, _LessThanComparable);
  return __lower_bound(__first, __last, __val,
		       __DISTANCE_TYPE(__first));
}

函数 __upper_bound 返回 __first 到 __last 的有序序列中从 __first 开始第一个大于给定值 __val 的元素的位置。如果存在大于 __val 的元素,则返回从 __first 开始第一个大于给定值 __val 的元素的位置。 否则返回值为 __last 。

template <class _ForwardIter, class _Tp, class _Distance>
_ForwardIter __upper_bound(_ForwardIter __first, _ForwardIter __last,
			   const _Tp& __val, _Distance*)
{
  _Distance __len = 0;
  distance(__first, __last, __len);
  _Distance __half;
  _ForwardIter __middle;

  while (__len > 0) {
    __half = __len >> 1;
    __middle = __first;
    advance(__middle, __half);
    if (__val < *__middle)
      __len = __half;
    else {
      __first = __middle;
      ++__first;
      __len = __len - __half - 1;
    }
  }
  return __first;
}

函数 upper_bound 返回从 __first 到 __last 的有序序列中第一个大于 __val 的元素的位置。

template <class _ForwardIter, class _Tp>
inline _ForwardIter upper_bound(_ForwardIter __first, _ForwardIter __last,
				const _Tp& __val) {
  __STL_REQUIRES(_ForwardIter, _ForwardIterator);
  __STL_REQUIRES_SAME_TYPE(_Tp,
      typename iterator_traits<_ForwardIter>::value_type);
  __STL_REQUIRES(_Tp, _LessThanComparable);
  return __upper_bound(__first, __last, __val,
		       __DISTANCE_TYPE(__first));
}

函数 __equal_range 返回有序序列中值等于 __val 的序列的起始和截止位置(起始位置的元素值为 __val,但结束位置的元素值不为 __val)。

也是用二分法,通过取中间元素的值和 __val 进行对比,并根据比对大小,来更新 __first 和 __len 的值。如果存在等于 __val 的元素,那么等于 __val 的元素组成的序列在整个循环过程中都在 __first 到 __first + len 之间。

循环过程中如果找到一个等于 __val 的元素,则调用 lower_bound 和 upper_bound 函数,两个函数的返回值就分别为等于 __val 的元素序列的起始位置和截止位置。如果 __first 到 __last 之间不存在等于 __val 的元素,则返回值为 pair(__last, __last)

template <class _ForwardIter, class _Tp, class _Distance>
pair<_ForwardIter, _ForwardIter>
__equal_range(_ForwardIter __first, _ForwardIter __last, const _Tp& __val,
	      _Distance*)
{
  _Distance __len = 0;
  distance(__first, __last, __len);
  _Distance __half;
  _ForwardIter __middle, __left, __right;

  while (__len > 0) {
    __half = __len >> 1;
    __middle = __first;
    advance(__middle, __half);
    if (*__middle < __val) {
      __first = __middle;
      ++__first;
      __len = __len - __half - 1;
    }
    else if (__val < *__middle)
      __len = __half;
    else {
      __left = lower_bound(__first, __middle, __val);
      advance(__first, __len);
      __right = upper_bound(++__middle, __first, __val);
      return pair<_ForwardIter, _ForwardIter>(__left, __right);
    }
  }
  return pair<_ForwardIter, _ForwardIter>(__first, __first);
}

函数 equal_range 返回从 __first 到 __last 的有序序列中值等于 __val 的元素序列的起始位置和截止位置。

template <class _ForwardIter, class _Tp>
inline pair<_ForwardIter, _ForwardIter>
equal_range(_ForwardIter __first, _ForwardIter __last, const _Tp& __val) {
  __STL_REQUIRES(_ForwardIter, _ForwardIterator);
  __STL_REQUIRES_SAME_TYPE(_Tp, 
       typename iterator_traits<_ForwardIter>::value_type);
  __STL_REQUIRES(_Tp, _LessThanComparable);
  return __equal_range(__first, __last, __val,
		       __DISTANCE_TYPE(__first));
}

函数 binary_search 在从 __first 到 __last 的有序序列中查找等于 __val 的元素,函数调用 lower_bound 函数来实现,如果存在等于 __val 的元素,则lower_bound 的会返回一个值为 __val 的位置,否则会返回 __last 或者一个值大于 __val 的位置。通过判断 lower_bound 的返回值可以判断 __first 到 __last 之间是否存在值为 __val 的元素。

template <class _ForwardIter, class _Tp>
bool binary_search(_ForwardIter __first, _ForwardIter __last,
		   const _Tp& __val) {
  __STL_REQUIRES(_ForwardIter, _ForwardIterator);
  __STL_REQUIRES_SAME_TYPE(_Tp,
	typename iterator_traits<_ForwardIter>::value_type);
  __STL_REQUIRES(_Tp, _LessThanComparable);
  _ForwardIter __i = lower_bound(__first, __last, __val);
  return __i != __last && !(__val < *__i);
}

函数 merge 将从 __first1 到 __last1 的有序序列和从 __first2 到 __last2 的有序序列进行合并。并且将合并的结果存储在 __result 开始的位置。

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 (__first1 != __last1 && __first2 != __last2) {
    if (*__first2 < *__first1) {
      *__result = *__first2;
      ++__first2;
    }
    else {
      *__result = *__first1;
      ++__first1;
    }
    ++__result;
  }
  return copy(__first2, __last2, copy(__first1, __last1, __result));
}

函数 __merge_without_buffer 将从 __first 到 __middle 的有序序列和从 __middle 到 __last 的有序序列进行合并,使得合并之后从 __first 到 __last 的序列是有序的。

令 __len1 为 __first 到 __middle 的距离,__len2 为 __middle 到 __last 的距离。如果 __len1 > __len2 ,令 __len11 = __len1 / 2。令 __first_cut 为 __first 之后的第 __len11 个位置。令 second_cut 为 __middle 到 __last 之间第一个大于或者等于 __first_cut 所在位置的元素的位置。

然后将 __first_cut 到 __middle 之间的内容和 __middle 到 __last 之间的内容通过 rotate 函数进行交换。返回值为 __new_middle。则此时 __first 到 __new_middle 之间的元素(小于或者等于交换之前 __first_cut 位置的元素值)都小于或者等于 __new_middle 到 __last 之间的元素(大于或者等于交换之前 __first_cut 所在位置的元素的元素值)。则递归的对 __first 到 __new_middle 和 __new_middle 到 __last 之间的元素调用 __merge_without_buffer 进行合并就可以了。

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);
}

STL 的 算法 (algo) 分析(一)</br> STL 的 算法 (algo) 分析(二)</br> STL 的 算法 (algo) 分析(三)</br> STL 的 算法 (algo) 分析(四)</br> STL 的 算法 (algo) 分析(五)</br> STL 的 算法 (algo) 分析(六)</br> STL 的 算法 (algo) 分析(七)</br> STL 的 算法 (algo) 分析(八)</br>