码迷,mamicode.com
首页 > 编程语言 > 详细

STL六大组件之——算法小小小小的解析

时间:2014-12-15 23:17:43      阅读:417      评论:0      收藏:0      [点我收藏+]

标签:io   ar   os   使用   sp   for   strong   on   数据   

参考自侯捷的《stl源码剖析》

stl算法主要分为非可变序列算法(指不直接修改其所操作的容器内容的算法),可变序列算法(指可以修改它们所操作的容器内容的算法),排序算法(包括对序列进行排序和合并的算法、搜索算法以及有序序列上的集合操作),数值算法(对容器内容进行数值计算)。

1.非可变序列算法

stl中的非可变序列算法有:for_each(), find(), find_if(), adjacent_find(), find_first_of(), count(), count_if(), mismatch(), equal(), search(), search_n(), find_end()。

for_each():它用来遍历一个序列中的元素,对指定序列中的每一个元素执行所定义的function操作,源码如下:
template <class _InputIter, class _Function>
_Function for_each(_InputIter __first, _InputIter __last, _Function __f) {
    __STL_REQUIRES(_InputIter, _InputIterator);
    for ( ; __first != __last; ++__first)
    __f(*__first);
    return __f;
}
注意他返回的是__f,可以这样用他:
struct print{
int count;
print(){count=0;}
void operator()(int x)
{ /* function*/;}
};
print p = for_each(lt.begin(),lt.end(),print());

find():用来查找指定序列中是否存在某个元素__val,并返回迭代器位置(如果不存在,返回end()),源码如下:
template <class _InputIter, class _Tp>
inline _InputIter find(_InputIter __first, _InputIter __last,
const _Tp& __val,
input_iterator_tag)
{
    while (__first != __last && !(*__first == __val))
    ++__first;
    return __first;
}

find_if():弄清楚find()的实现原理,就不难理解find_if(),这个函数返回使定义的函数__pred为真时迭代器的位置,同样如果全为假,则返回end(),源码如下:
template <class _InputIter, class _Predicate>
inline _InputIter find_if(_InputIter __first, _InputIter __last,
_Predicate __pred,
input_iterator_tag)
{
    while (__first != __last && !__pred(*__first))
    ++__first;
    return __first;
}

adjacent_find():这个函数用来查找指定序列中是否有两个连续的元素相等(或使__pred为真),并返回迭代器的位置,注意是返回第一个元素的位置,如果没有,则返回end().函数有两个形式,分别是相等和谓词判断,源码如下:
/* 没有谓词判断,即只判断相等否*/
template <class _ForwardIter>
_ForwardIter adjacent_find(_ForwardIter __first, _ForwardIter __last) {
__STL_REQUIRES(_ForwardIter, _ForwardIterator);
__STL_REQUIRES(typename iterator_traits<_ForwardIter>::value_type,
_EqualityComparable);
if (__first == __last)
return __last;
_ForwardIter __next = __first;
while(++__next != __last) {
if (*__first == *__next)
return __first;
__first = __next;
}
return __last;
}
/*有谓词判断,是否满足__pred*/
template <class _ForwardIter, class _BinaryPredicate>
_ForwardIter adjacent_find(_ForwardIter __first, _ForwardIter __last,
_BinaryPredicate __binary_pred) {
__STL_REQUIRES(_ForwardIter, _ForwardIterator);
__STL_BINARY_FUNCTION_CHECK(_BinaryPredicate, bool,
typename iterator_traits<_ForwardIter>::value_type,
typename iterator_traits<_ForwardIter>::value_type);
if (__first == __last)
return __last;
_ForwardIter __next = __first;
while(++__next != __last) {
if (__binary_pred(*__first, *__next))
return __first;
__first = __next;
}
return __last;
}
谓词判断注意:__pred函数是需要两个参数的。

find_first_of():此函数用于查找指定序列中的元素是否存在一个元素,也在另一个序列元素中(就是查找是否存在交集),或是否各有一元素满足指定函数__comp,源码如下:
// find_first_of, with and without an explicitly supplied comparison function.

template <class _InputIter, class _ForwardIter>
_InputIter find_first_of(_InputIter __first1, _InputIter __last1,
_ForwardIter __first2, _ForwardIter __last2)
{
    __STL_REQUIRES(_InputIter, _InputIterator);
    __STL_REQUIRES(_ForwardIter, _ForwardIterator);
    __STL_REQUIRES_BINARY_OP(_OP_EQUAL, bool,
    typename iterator_traits<_InputIter>::value_type,
    typename iterator_traits<_ForwardIter>::value_type);

    for ( ; __first1 != __last1; ++__first1)
        for (_ForwardIter __iter = __first2; __iter != __last2; ++__iter)
            if (*__first1 == *__iter)
                return __first1;
    return __last1;
}

template <class _InputIter, class _ForwardIter, class _BinaryPredicate>
_InputIter find_first_of(_InputIter __first1, _InputIter __last1,
_ForwardIter __first2, _ForwardIter __last2,
_BinaryPredicate __comp)
{
    __STL_REQUIRES(_InputIter, _InputIterator);
    __STL_REQUIRES(_ForwardIter, _ForwardIterator);
    __STL_BINARY_FUNCTION_CHECK(_BinaryPredicate, bool,
    typename iterator_traits<_InputIter>::value_type,
    typename iterator_traits<_ForwardIter>::value_type);

    for ( ; __first1 != __last1; ++__first1)
        for (_ForwardIter __iter = __first2; __iter != __last2; ++__iter)
            if (__comp(*__first1, *__iter))
                return __first1;
    return __last1;
}

count():此函数用于计算某个元素在指定序列中出现的次数,此函数有两种形式,第二种是把指定的n以引用的方式传进去,从而得出n。源码不难,很好理解,如下:
/*这个是传应用n,是没有返回值的*/
template <class _InputIter, class _Tp, class _Size>
void count(_InputIter __first, _InputIter __last, const _Tp& __value,
_Size& __n) {
    __STL_REQUIRES(_InputIter, _InputIterator);
    __STL_REQUIRES(typename iterator_traits<_InputIter>::value_type,
    _EqualityComparable);
    __STL_REQUIRES(_Tp, _EqualityComparable);
    for ( ; __first != __last; ++__first)
        if (*__first == __value)
            ++__n;
}
/*这个只有三个参数,是有N作为返回值的*/
template <class _InputIter, class _Tp>
typename iterator_traits<_InputIter>::difference_type
count(_InputIter __first, _InputIter __last, const _Tp& __value) {
    __STL_REQUIRES(_InputIter, _InputIterator);
    __STL_REQUIRES(typename iterator_traits<_InputIter>::value_type,
    _EqualityComparable);
    __STL_REQUIRES(_Tp, _EqualityComparable);
    typename iterator_traits<_InputIter>::difference_type __n = 0;
    for ( ; __first != __last; ++__first)
        if (*__first == __value)
            ++__n;
    return __n;
}

count_if():和count()一样,只不过是多了一个谓词判断,查找的是满足谓词判断__pred的值的个数,源码如下:
/*引用,没有返回值*/
template <class _InputIter, class _Predicate, class _Size>
void count_if(_InputIter __first, _InputIter __last, _Predicate __pred,
_Size& __n) {
    __STL_REQUIRES(_InputIter, _InputIterator);
    __STL_UNARY_FUNCTION_CHECK(_Predicate, bool,
    typename iterator_traits<_InputIter>::value_type);
        for ( ; __first != __last; ++__first)
            if (__pred(*__first))
                ++__n;
}
/*有返回值*/
template <class _InputIter, class _Predicate>
typename iterator_traits<_InputIter>::difference_type
count_if(_InputIter __first, _InputIter __last, _Predicate __pred) {
    __STL_REQUIRES(_InputIter, _InputIterator);
    __STL_UNARY_FUNCTION_CHECK(_Predicate, bool,
    typename iterator_traits<_InputIter>::value_type);
    typename iterator_traits<_InputIter>::difference_type __n = 0;
    for ( ; __first != __last; ++__first)
        if (__pred(*__first))
            ++__n;
    return __n;
}

mismatch():此函数用于找出指定序列中首个不等于另一个序列(或首个使谓词判断为假)的元素的位置,注意是返回的两个地址。

equal():和mismatch函数一样,不过他返回的是bool值,false和true。

search():此函数在一个指定的序列中匹配另一个序列,有两种形式,同上,有一种是谓词判断的:源码如下:
template <class _ForwardIter1, class _ForwardIter2>
_ForwardIter1 search(_ForwardIter1 __first1, _ForwardIter1 __last1,
_ForwardIter2 __first2, _ForwardIter2 __last2)
{
    __STL_REQUIRES(_ForwardIter1, _ForwardIterator);
    __STL_REQUIRES(_ForwardIter2, _ForwardIterator);
    __STL_REQUIRES_BINARY_OP(_OP_EQUAL, bool,
    typename iterator_traits<_ForwardIter1>::value_type,
    typename iterator_traits<_ForwardIter2>::value_type);

    // Test for empty ranges
    if (__first1 == __last1 || __first2 == __last2)
        return __first1;

    // Test for a pattern of length 1.
    _ForwardIter2 __tmp(__first2);
    ++__tmp;
    if (__tmp == __last2)
        return find(__first1, __last1, *__first2);

    // General case.
    _ForwardIter2 __p1, __p;
    __p1 = __first2; ++__p1;
    _ForwardIter1 __current = __first1;

    while (__first1 != __last1) {
    __first1 = find(__first1, __last1, *__first2);
    if (__first1 == __last1)
        return __last1;

    __p = __p1;
    __current = __first1;
    if (++__current == __last1)
        return __last1;

    while (*__current == *__p) {
    if (++__p == __last2)
        return __first1;
    if (++__current == __last1)
        return __last1;
    }

    ++__first1;
    }
    return __first1;
}

template <class _ForwardIter1, class _ForwardIter2, class _BinaryPred>
_ForwardIter1 search(_ForwardIter1 __first1, _ForwardIter1 __last1,
_ForwardIter2 __first2, _ForwardIter2 __last2,
_BinaryPred __predicate)
{
    __STL_REQUIRES(_ForwardIter1, _ForwardIterator);
    __STL_REQUIRES(_ForwardIter2, _ForwardIterator);
    __STL_BINARY_FUNCTION_CHECK(_BinaryPred, bool,
    typename iterator_traits<_ForwardIter1>::value_type,
    typename iterator_traits<_ForwardIter2>::value_type);

    // Test for empty ranges
    if (__first1 == __last1 || __first2 == __last2)
    return __first1;

    // Test for a pattern of length 1.
    _ForwardIter2 __tmp(__first2);
    ++__tmp;
    if (__tmp == __last2) {
    while (__first1 != __last1 && !__predicate(*__first1, *__first2))
        ++__first1;
    return __first1;   
    }

    // General case.
    _ForwardIter2 __p1, __p;
    __p1 = __first2; ++__p1;
    _ForwardIter1 __current = __first1;

    while (__first1 != __last1) {
    while (__first1 != __last1) {
    if (__predicate(*__first1, *__first2))
        break;
    ++__first1;
    }
    while (__first1 != __last1 && !__predicate(*__first1, *__first2))
        ++__first1;
    if (__first1 == __last1)
        return __last1;

    __p = __p1;
    __current = __first1;
    if (++__current == __last1) return __last1;

    while (__predicate(*__current, *__p)) {
        if (++__p == __last2)
            return __first1;
        if (++__current == __last1)
            return __last1;
    }

    ++__first1;
    }
    return __first1;
}

search_n():他所做的工作是在指定序列中查找是否有n个连续元素与给定元素相等(或使得谓词判断为真),使用时要注意参数顺序,源码余下:
template <class _ForwardIter, class _Integer, class _Tp>
_ForwardIter search_n(_ForwardIter __first, _ForwardIter __last,
_Integer __count, const _Tp& __val) {
__STL_REQUIRES(_ForwardIter, _ForwardIterator);
__STL_REQUIRES(typename iterator_traits<_ForwardIter>::value_type,
_EqualityComparable);
__STL_REQUIRES(_Tp, _EqualityComparable);

if (__count <= 0)
return __first;
else {
__first = find(__first, __last, __val);
while (__first != __last) {
_Integer __n = __count - 1;
_ForwardIter __i = __first;
++__i;
while (__i != __last && __n != 0 && *__i == __val) {
++__i;
--__n;
}
if (__n == 0)
return __first;
else
__first = find(__i, __last, __val);
}
return __last;
}
}

template <class _ForwardIter, class _Integer, class _Tp, class _BinaryPred>
_ForwardIter search_n(_ForwardIter __first, _ForwardIter __last,
_Integer __count, const _Tp& __val,
_BinaryPred __binary_pred) {
__STL_REQUIRES(_ForwardIter, _ForwardIterator);
__STL_BINARY_FUNCTION_CHECK(_BinaryPred, bool,
typename iterator_traits<_ForwardIter>::value_type, _Tp);
if (__count <= 0)
return __first;
else {
while (__first != __last) {
if (__binary_pred(*__first, __val))
break;
++__first;
}
while (__first != __last) {
_Integer __n = __count - 1;
_ForwardIter __i = __first;
++__i;
while (__i != __last && __n != 0 && __binary_pred(*__i, __val)) {
++__i;
--__n;
}
if (__n == 0)
return __first;
else {
while (__i != __last) {
if (__binary_pred(*__i, __val))
break;
++__i;
}
__first = __i;
}
}
return __last;
}
}

find_end():此函数用于找出在一个指定序列中另一个序列的最后一个匹配序列的位置,如果没有则返回last(end()),仍然是有两种形式,现只给出一种即可:

template <class _ForwardIter1, class _ForwardIter2>
_ForwardIter1 __find_end(_ForwardIter1 __first1, _ForwardIter1 __last1,
_ForwardIter2 __first2, _ForwardIter2 __last2,
forward_iterator_tag, forward_iterator_tag)
{
if (__first2 == __last2)
return __last1;
else {
_ForwardIter1 __result = __last1;
while (1) {
_ForwardIter1 __new_result
= search(__first1, __last1, __first2, __last2);
if (__new_result == __last1)
return __result;
else {
__result = __new_result;
__first1 = __new_result;
++__first1;
}
}
}

2. 可变序列算法

stl的可变序列算法很多,有三十个左右,现在只看看较常用的几个算法:copy, copy_backward, swap, iter_swap, swap_ranges, transform, replace_if, fill, fill_n, generate, generate_n, remove,reverse, reverse_copy.

copy():区间复制函数,将原区间内的元素一次复制到目的区间,三个参数是first,last,result,其中的result是目的区间的首地址,源码如下:

template <class _InputIter, class _OutputIter, class _Distance>
inline _OutputIter __copy(_InputIter __first, _InputIter __last,
                          _OutputIter __result,
                          input_iterator_tag, _Distance*)
{
  for ( ; __first != __last; ++__result, ++__first)
      *__result = *__first;
  return __result;
}


copy_backward():与copy算法相似,也是将原区间内的元素一次复制到目的区间,但元素的复制顺序是从后向前的,但要注意你所输入的result是目的区间的结束位置,所以,copy_backward和copy的结果是一样的,只不过是内部的实现细节不一样罢了,源码如下:

template <class _BidirectionalIter1, class _BidirectionalIter2,
          class _Distance>
inline _BidirectionalIter2 __copy_backward(_BidirectionalIter1 __first,
                                           _BidirectionalIter1 __last,
                                           _BidirectionalIter2 __result,
                                           bidirectional_iterator_tag,
                                           _Distance*)
{
  while (__first != __last)
      *--__result = *--__last;
  return __result;
}

swap():交换元素(这两个元素是以引用的形式传进来的):

template <class _Tp>
inline void swap(_Tp& __a, _Tp& __b) {
  _Tp __tmp = __a;
  __a = __b;
  __b = __tmp;
}


iter_swap():函数是迭代器元素交换,参数是两个迭代器指针,注意:数据必须是可交换的:

template <class _ForwardIter1, class _ForwardIter2, class _Tp>
inline void __iter_swap(_ForwardIter1 __a, _ForwardIter2 __b, _Tp*) {
  _Tp __tmp = *__a;
  *__a = *__b;
  *__b = __tmp;
}

template <class _ForwardIter1, class _ForwardIter2>
inline void iter_swap(_ForwardIter1 __a, _ForwardIter2 __b) {
  __iter_swap(__a, __b, __VALUE_TYPE(__a));
}


swap_ranges():顾名思意,他的作用是将原区间与目的区间的元素作交换,当然前提是元素必须是可交换的,有三个参数:first,last,result,其中result是目的区间的首地址,源码如下:

template <class _ForwardIter1, class _ForwardIter2>
_ForwardIter2 swap_ranges(_ForwardIter1 __first1, _ForwardIter1 __last1,
                          _ForwardIter2 __first2) {
  for ( ; __first1 != __last1; ++__first1, ++__first2)
      iter_swap(__first1, __first2);
  return __first2;
}

 

transform():这个函数非常有用,可以替代你做不少复杂的工作,目的是将原区间的元素依次通过操作的到目的元素,这些结果是要存 放到目的区间的,他有两个实现(一)op为一元操作符,故只能接受一个参数,transform的四个参数依次是 first,last,result,op其中result是目的区间的首地址,(二)op为二元操作符,故原函数需要多一个参数,五个参数依次 是:first,last,first,result,op,第三个first是第二个区间的首地址,result是目的区间的首地址,op为二元操作符:

template <class _InputIter, class _OutputIter, class _UnaryOperation>
_OutputIter transform(_InputIter __first, _InputIter __last,
                      _OutputIter __result, _UnaryOperation __opr) {
  for ( ; __first != __last; ++__first, ++__result)
      *__result = __opr(*__first);
  return __result;
}

template <class _InputIter1, class _InputIter2, class _OutputIter,
          class _BinaryOperation>
_OutputIter transform(_InputIter1 __first1, _InputIter1 __last1,
                      _InputIter2 __first2, _OutputIter __result,
                      _BinaryOperation __binary_op) {
  for ( ; __first1 != __last1; ++__first1, ++__first2, ++__result)
      *__result = __binary_op(*__first1, *__first2);
  return __result;
}


replace():替换函数,将原区间内为old的元素全部替换为new元素,old和new是需要函数参数提供的:

template <class _ForwardIter, class _Tp>
void replace(_ForwardIter __first, _ForwardIter __last,
             const _Tp& __old_value, const _Tp& __new_value) {
  for ( ; __first != __last; ++__first)
      if (*__first == __old_value)
          *__first = __new_value;
}


replace_if():很容易理解,这个函数将原区间内满足一元谓词判断的元素全部替换为new元素:

template <class _ForwardIter, class _Predicate, class _Tp>
void replace_if(_ForwardIter __first, _ForwardIter __last,
                _Predicate __pred, const _Tp& __new_value) {
  for ( ; __first != __last; ++__first)
      if (__pred(*__first))
          *__first = __new_value;
}


fill():填充函数,将原区间全部填满你所指定的元素,源码如下:

template <class _ForwardIter, class _Tp>
void fill(_ForwardIter __first, _ForwardIter __last, const _Tp& __value) {
  for ( ; __first != __last; ++__first)
      *__first = __value;
}

fill_n():也是填充,是填满[first,first+n]区间内的元素,源码如下:

template <class _OutputIter, class _Size, class _Tp>
_OutputIter fill_n(_OutputIter __first, _Size __n, const _Tp& __value) {
  for ( ; __n > 0; --__n, ++__first)
      *__first = __value;
  return __first;
}

generate()和generate_n():
两个函数都是生成函数,用指定的生成器(函数)来填满指定区间,为了便于说明,先看看两个函数的源码,之所以把这两个函数放到一起,是因为他们长的太像了,一起讨论方便:

template <class _ForwardIter, class _Generator>
void generate(_ForwardIter __first, _ForwardIter __last, _Generator __gen) {
  for ( ; __first != __last; ++__first)
      *__first = __gen();
}

template <class _OutputIter, class _Size, class _Generator>
_OutputIter generate_n(_OutputIter __first, _Size __n, _Generator __gen) {
  for ( ; __n > 0; --__n, ++__first)
      *__first = __gen();
  return __first;
}

其中的一句话:*__first = gen(),可以看出,gen()函数是没有参数的,所以如果没有一个关于gen()的全局变量,gen()函数生成的结果是一样的,所以做好对gen()检查好了再用,不然有可能整个区间的元素是一样的。


remove_copy():将原区间中不等于指定value的元素复制到目的区间,源码如下:

template <class _InputIter, class _OutputIter, class _Tp>
_OutputIter remove_copy(_InputIter __first, _InputIter __last,
                        _OutputIter __result, const _Tp& __value) {
  for ( ; __first != __last; ++__first)
      if (*__first != __value) {
          *__result = *__first;
          ++__result;
      }
  return __result;
}


remove_copy_if():这个函数将remove_copy中的value替换为一个谓词判断,只有不满足谓词判断的元素才会被复制到目的区间内,源码如下:

template <class _InputIter, class _OutputIter, class _Predicate>
_OutputIter remove_copy_if(_InputIter __first, _InputIter __last,
                           _OutputIter __result, _Predicate __pred) {
  for ( ; __first != __last; ++__first)
      if (!__pred(*__first)) {
          *__result = *__first;
          ++__result;
      }
  return __result;
}

remove():这个算法是将容器中等于value的元素全部去掉,同样是先看看源码,在对他作分析:

_ForwardIter remove(_ForwardIter __first, _ForwardIter __last,
                    const _Tp& __value) {
  __first = find(__first, __last, __value);
  _ForwardIter __i = __first;
  return __first == __last ? __first
                           : remove_copy(++__i, __last, __first, __value);
}


其中先找出第一个满足value的值的位置,再作判断,然后调用remove_copy()函数将不等于value的元素复制到新的区间 上,可以看到,无论是空间或者是时间,这个算法的执行都不怎么好,remove_copy()操作浪费了太多的时间和空间,不过考虑到他的通用性,这个函 数还是不错的。


reverse():函数的功能是翻转指定区间的全部元素,算法思想很简单就能想到,不过源码写的很有技巧性,看后可以让人眼前一亮的感觉,源码分析:

template <class _BidirectionalIter>
void __reverse(_BidirectionalIter __first, _BidirectionalIter __last,
               bidirectional_iterator_tag) {
  while (true)
      if (__first == __last || __first == --__last)
          return;
      else
          iter_swap(__first++, __last);
}


reverse_copy():不对原区间的元素进行操作,而是将其翻转输出到指定的目的区间,源码如下:

template <class _BidirectionalIter, class _OutputIter>
_OutputIter reverse_copy(_BidirectionalIter __first,
                            _BidirectionalIter __last,
                            _OutputIter __result) {
  while (__first != __last) {
      --__last;
      *__result = *__last;
      ++__result;
  }
  return __result;
}

3.排序算法

由于内容太多,只列出典型部分啦:

Insertion Sort算法的复杂度为O(N^2),最好情况下时间复杂度为O(N)。在数据量很少时,尤其还是在序列“几近排序但尚未完成”时,有着很不错的效果。

// 默认以渐增方式排序
    template <class RandomAccessIterator>
    void __insertion_sort(RandomAccessIterator first,
        RandomAccessIterator last)
    {
        if (first == last) return;
                // --- insertion sort 外循环 ---
        for (RandomAccessIterator i = first + 1; i != last; ++i)
            __linear_insert(first, i, value_type(first));
        // 以上,[first,i) 形成一个子区间
    }

    template <class RandomAccessIterator, class T>
    inline void __linear_insert(RandomAccessIterator first,
        RandomAccessIterator last, T*)
    {
        T value = *last;      // 记录尾元素
        if (value < *first){      // 尾比头还小 (注意,头端必为最小元素)
            copy_backward(first, last, last + 1);    // 将整个区间向右移一个位置
            *first = value;      // 令头元素等于原先的尾元素值
        }
        else    // 尾不小于头
            __unguarded_linear_insert(last, value);
    }

    template <class RandomAccessIterator, class T>
    void __unguarded_linear_insert(RandomAccessIterator last, T value)
    {
        RandomAccessIterator next = last;
        --next;

        // --- insertion sort 内循环 ---
        // 注意,一旦不再出现逆转对(inversion),循环就可以结束了
        while (value < *next){    // 逆转对(inversion)存在
            *last = *next;        // 调整
            last = next;        // 调整迭代器   
            --next;            // 左移一个位置
        }
        *last = value;            // value 的正确落脚处
    }

Quick Sort平均复杂度为O(NlogN),可是最坏情况下将达O(N^2)。

Median-of-Three(三点中值):因为任何元素都可以当做枢轴(pivot),为了避免元素输入时不够随机带来的恶化效应,最理想最稳当的方式就是取整个序列的投、尾、中央三个元素的中值(median)作为枢轴。

// 返回 a,b,c之居中者
    template <class T>
    inline const T& __median(const T& a, const T& b, const T& c)
    {
        if (a < b)
            if (b < c)        // a < b < c
                return b;
            else if (a < c)    // a < b, b >= c, a < c  -->     a < b <= c
                return c;
            else            // a < b, b >= c, a >= c    -->     c <= a < b
                return a;
        else if (a < c)        // c > a >= b
            return a;
        else if (b < c)        // a >= b, a >= c, b < c    -->   b < c <= a
            return c;
        else                // a >= b, a >= c, b >= c    -->      c<= b <= a
            return b;        
    }
template <class RandomAccessIterator, class T>
    RandomAccessIterator __unguarded_partition(
                                    RandomAccessIterator first,
                                    RandomAccessIterator last,
                                    T pivot)
    {
        while(true){
            while (*first < pivot) ++first;    // first 找到 >= pivot的元素就停
            --last;

            while (pivot < *last) --last;    // last 找到 <=pivot

            if (!(first < last)) return first;    // 交错,结束循环   
        //    else
            iter_swap(first,last);                // 大小值交换
            ++first;                            // 调整
        }
    }

Heap Sortheap_sort的任务是找出middle-first个最小元素,因此,首先界定出区间[first,middle),并利用make_heap()将它组织成一个max-heap,然后就可以讲[middle,last)中的每一个元素拿来与max-heap的最大值比较(max-heap的最大值就在第一个元素);如果小于该最大值,就互换位置并重新保持max-heap的状态。如此一来,当我们走遍整个[middle,last)时,较大的元素都已经被抽离出[first,middle),这时候再以sort_heap()将[first,middle)做一次排序。

// paitial_sort的任务是找出middle - first个最小元素。
    template <class RandomAccessIterator>
    inline void partial_sort(RandomAccessIterator first,
                             RandomAccessIterator middle,
                             RandomAccessIterator last)
    {
        __partial_sort(first, middle, last, value_type(first));
    }
    template <class RandomAccessIterator,class T>
    inline void __partial_sort(RandomAccessIterator first,
                            RandomAccessIterator middle,
                            RandomAccessIterator last, T*)
    {
        make_heap(first, middle); // 默认是max-heap,即root是最大的
        for (RandomAccessIterator i = middle; i < last; ++i)
            if (*i < *first)
                __pop_heap(first, middle, i, T(*i), distance_type(first));
        sort_heap(first,middle);
    }

Intro Sort: 不当的枢轴选择,导致不当的分割,导致Quick Sort恶化为O(N^2)。David R. Musser于1996年提出一种混合式排序算法,Introspective Sorting。其行为在大部分情况下几乎与 median-of-3 Quick Sort完全相同。但是当分割行为(partitioning)有恶化为二次行为倾向时,能自我侦测,转而改用Heap Sort,使效率维持在O(NlogN),又比一开始就使用Heap Sort来得好。大部分STL的sort内部其实就是用的IntroSort。

template <class RandomAccessIterator>
    inline void sort(RandomAccessIterator first,
                    RandomAccessIterator last)
    {
        if (first != last){
            __introsort_loop(first, last, value_type(first), __lg(last-first)*2);
            __final_insertion_sort(first,last);
        }
                                                                                                       
    }
    // __lg()用来控制分割恶化的情况
    // 找出2^k <= n 的最大值,例:n=7得k=2; n=20得k=4
    template<class Size>
    inline Size __lg(Size n)
    {
        Size k;
        for (k = 0; n > 1; n >>= 1)
            ++k;
        return k;
    }

        // 当元素个数为40时,__introsort_loop的最后一个参数
        // 即__lg(last-first)*2是5*2,意思是最多允许分割10层。

    const int  __stl_threshold = 16;

    template <class RandomAccessIterator, class T, class Size>
    void __introsort_loop(RandomAccessIterator first,
                    RandomAccessIterator last, T*,
                    Size depth_limit)
    {
        while (last - first > __stl_threshold){        // > 16
            if (depth_limit == 0){                    // 至此,分割恶化
                partial_sort(first, last, last);    // 改用 heapsort
                return;
            }

            --depth_limit;
            // 以下是 median-of-3 partition,选择一个够好的枢轴并决定分割点
            // 分割点将落在迭代器cut身上
            RandomAccessIterator cut = __unguarded_partition
                (first, last, T(__median(*first,
                                         *(first + (last - first)/2),
                                        *(last - 1))));

            // 对右半段递归进行sort
            __introsort_loop(cut,last,value_type(first), depth_limit);

            last = cut;
            // 现在回到while循环中,准备对左半段递归进行sort
            // 这种写法可读性较差,效率也并没有比较好
        }
    }

    函数一开始就判断序列大小,通过个数检验之后,再检测分割层次,若分割层次超过指定值,就改用partial_sort(),即Heap sort。都通过了这些校验之后,便进入与Quick Sort完全相同的程序。当__introsort_loop()结束,[first,last)内有多个“元素个数少于或等于”16的子序列,每个序列有相当程序的排序,但尚未完全排序(因为元素个数一旦小于 __stl_threshold,就被中止了)。回到母函数,再进入__final_insertion_sort():

template <class RandomAccessIterator>
    void __final_insertion_sort(RandomAccessIterator first,
        RandomAccessIterator last)
    {
        if (last - first > __stl_threshold){  
            // > 16
            // 一、[first,first+16)进行插入排序
            // 二、调用__unguarded_insertion_sort,实质是直接进入插入排序内循环,
            //       *参见Insertion sort 源码
            __insertion_sort(first,first + __stl_threshold);
            __unguarded_insertion_sort(first + __stl_threshold, last);
        }
        else
            __insertion_sort(first, last);
    }

    template <class RandomAccessIterator>
    inline void __unguarded_insertion_sort(RandomAccessIterator first,
        RandomAccessIterator last)
    {
        __unguarded_insertion_sort_aux(first, last, value_type(first));
    }

    template <class RandomAccessIterator, class T>

    void __unguarded_insertion_sort_aux(RandomAccessIterator first,
        RandomAccessIterator last,
        T*)
    {
        for (RandomAccessIterator i = first; i != last; ++i)
            __unguarded_linear_insert(i, T(*i));
    }

4.数值算法

列举一下,我也没看多少:

accumulate:

template<class InputIterator, class Type>
Type accumulate(
InputIterator _First,
InputIterator _Last,
Type _Val
);
template<class InputIterator, class Type, class BinaryOperation>
Type accumulate(
InputIterator _First,
InputIterator _Last,
Type _Val,
BinaryOperation _Binary_op
);

inner_product:第二个序列的个数必须大于等于第一个序列的个数。因为,inner_product内部实现是以第一序列的元素个数为依据的,将两个序列都走了一遍。可能实现为while( _First1!=_Last1){...}或者n=_Last1-_First1;while(n>0){...}

template<class InputIterator1, class InputIterator2, class Type>
Type inner_product(
InputIterator1 _First1,
InputIterator1 _Last1,
InputIterator2 _First2,
Type _Val
);
template<class InputIterator1, class InputIterator2, class Type,
class BinaryOperation1, class BinaryOperation2>
Type inner_product(
InputIterator1 _First1,
InputIterator1 _Last1,
InputIterator2 _First2,
Type _Val,
BinaryOperation1 _Binary_op1,
BinaryOperation2 _Binary_op2
);

adjacent_difference

template<class InputIterator, class OutIterator>
OutputIterator adjacent_difference(
InputIterator _First,
InputIterator _Last,
OutputIterator _Result
);
template<class InputIterator, class OutIterator, class BinaryOperation>
OutputIterator adjacent_difference(
InputIterator _First,
InputIterator _Last,
OutputIterator _Result,
BinaryOperation _Binary_op
);

partial_sumpartial_sum与先前介绍的adjacent_difference互为逆运算。如果对区间值1,2,3,4,5执行partial_sum,获 得结果为1,3,6,10,15,再对此结果执行adjacent_difference,便会获得原始区间值1,2,3,4,5。反之亦然。

template<class InputIterator, class OutIt>
OutputIterator partial_sum(
InputIterator _First,
InputIterator _Last,
OutputIterator _Result
);
template<class InputIterator, class OutIt, class Fn2>
OutputIterator partial_sum(
InputIterator _First,
InputIterator _Last,
OutputIterator _Result,
BinaryOperation _Binary_op
);

STL六大组件之——算法小小小小的解析

标签:io   ar   os   使用   sp   for   strong   on   数据   

原文地址:http://www.cnblogs.com/geekpaul/p/4165934.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!