SGISTL源码阅读二十七 基本算法 (stl_algobase.h)

SGISTL源码阅读二十七 基本算法 (stl_algobase.h)

前言

SGISTL将一些基本常用的算法定义于stl_algobase.h中,其他的一些算法定义于slt_algo.h中,下面我们分析stl_algobase.h中的一些算法。


深入源码

__iter_swap&&swap
//交换两个迭代器
//版本1
template <class ForwardIterator1, class ForwardIterator2, class T>
inline void __iter_swap(ForwardIterator1 a, ForwardIterator2 b, T*) {
  T tmp = *a;
  *a = *b;
  *b = tmp;
}
//版本2
template <class ForwardIterator1, class ForwardIterator2>
inline void iter_swap(ForwardIterator1 a, ForwardIterator2 b) {
  //获取元素类型后调用版本1
  __iter_swap(a, b, value_type(a));
}
//传入引用
//交换a,b的值
template <class T>
inline void swap(T& a, T& b) {
  T tmp = a;
  a = b;
  b = tmp;
}
min&&max
//版本1
template <class T>
inline const T& min(const T& a, const T& b) {
  return b < a ? b : a;
}
//版本2
//传入比较器
//比较两个元素,返回较小的值
template <class T, class Compare>
inline const T& min(const T& a, const T& b, Compare comp) {
  return comp(b, a) ? b : a;
}
//版本1
template <class T>
inline const T& max(const T& a, const T& b) {
  return  a < b ? b : a;
}
//版本2
//传入比较器
//比较两个元素,返回较大的值
template <class T, class Compare>
inline const T& max(const T& a, const T& b, Compare comp) {
  return comp(a, b) ? b : a;
}
copy

copy算法可将指定区间[first, last)内的元素复制到输出区间[result, result + (last - first))内。它时常被调用,所以一个需要有一个高效率的算法。比如说,如果有trivial operator,我们可以使用内存直接复制,调用memmove;用比较迭代器来控制复制过程循环的条件肯定是没有直接用元素数量来控制效率高的。
看代码量就知道copy的实现相当复杂,先了解一下它的整体。这里直接使用了《STL源码剖析》中P315的一张图,直接看可能有些费力,结合图片阅读源码(图中箭头的意思是不同的版本调用的其他函数)。
在这里插入图片描述

template <class InputIterator, class OutputIterator>
inline OutputIterator __copy(InputIterator first, InputIterator last,
                             OutputIterator result, input_iterator_tag)
{
  //将[first, last)内的元素复制到输出区间[result, result + (last - first))内
  //比较迭代器判断遍历是否结束
  for ( ; first != last; ++result, ++first)
    *result = *first;
  return result;
}
//提供了Distance作为参数,可直接通过元素个数进行循环控制
//但是迭代器类型要求为RandomAccessIterator
template <class RandomAccessIterator, class OutputIterator, class Distance>
inline OutputIterator
__copy_d(RandomAccessIterator first, RandomAccessIterator last,
         OutputIterator result, Distance*)
{
  //循环控制条件由n控制
  //效率高于使用迭代器作比较
  for (Distance n = last - first; n > 0; --n, ++result, ++first)
    *result = *first;
  return result;
}

template <class RandomAccessIterator, class OutputIterator>
inline OutputIterator
//迭代器类型为RandomAccessIterator
__copy(RandomAccessIterator first, RandomAccessIterator last,
       OutputIterator result, random_access_iterator_tag)
{
  //调用__copy_d
  return __copy_d(first, last, result, distance_type(first));
}
/* __copy_dispatch有泛化版以及偏特化版,它重载了()操作符
 * 内部调用__copy函数
 */
 //完全泛化版本
template <class InputIterator, class OutputIterator>
struct __copy_dispatch
{
  //重载了()操作符,调用__copy函数
  OutputIterator operator()(InputIterator first, InputIterator last,
                            OutputIterator result) {
    return __copy(first, last, result, iterator_category(first));
  }
};
#ifdef __STL_CLASS_PARTIAL_SPECIALIZATION

/* 供下面的__copy_dispatch调用
 * 通过traits技法判断类型T是否具有trivial_assignment_operator
 * 从而选取比较有效率的做法
 */
template <class T>
inline T* __copy_t(const T* first, const T* last, T* result, __true_type) {
  //进入这个函数证明有 trivial operator (__true_type)
  //所以我们直接采用memmove函数来达到最佳效率
  memmove(result, first, sizeof(T) * (last - first));
  return result + (last - first);
}

template <class T>
inline T* __copy_t(const T* first, const T* last, T* result, __false_type) {
  //进入到这个函数证明有 no-trivial operator (__false_type)
  //所以无法简单的拷贝内存上的数据,只能调用__copy_d函数进行处理了
  return __copy_d(first, last, result, (ptrdiff_t*) 0);
}
//__copy_dispatch的特化版本1,两个参数为指针T*形式
template <class T>
struct __copy_dispatch<T*, T*>
{
  T* operator()(T* first, T* last, T* result) {
    //判断是否有trivial operator
    typedef typename __type_traits<T>::has_trivial_assignment_operator t;
    //调用__copy_t
    return __copy_t(first, last, result, t());
  }
};
//__copy_dispatch的特化版本2,参数为一个为const T*形式,一个为T*形式
template <class T>
struct __copy_dispatch<const T*, T*>
{
  T* operator()(const T* first, const T* last, T* result) {
    //判断是否有trivial operator
    typedef typename __type_traits<T>::has_trivial_assignment_operator t;
    //调用__copy_t
    return __copy_t(first, last, result, t());
  }
};

//以下为copy函数,它也有不同的泛化,特化版本

//泛化版本
#endif /* __STL_CLASS_PARTIAL_SPECIALIZATION */
template <class InputIterator, class OutputIterator>
inline OutputIterator copy(InputIterator first, InputIterator last,
                           OutputIterator result)
{
  //调用__copy_dispatch
  return __copy_dispatch<InputIterator,OutputIterator>()(first, last, result);
}
//特化版本(const char*)
inline char* copy(const char* first, const char* last, char* result) {
  memmove(result, first, last - first);
  return result + (last - first);
}
特化版本(const wchar*)
inline wchar_t* copy(const wchar_t* first, const wchar_t* last,
                     wchar_t* result) {
  memmove(result, first, sizeof(wchar_t) * (last - first));
  return result + (last - first);
}

copy_backward

这个算法的技巧和copy十分类似,顾名思义,就是反向拷贝。
[first, last)区间的元素,以逆行的方向复制到以result-1为起点,方向也为逆行的区间上

template <class BidirectionalIterator1, class BidirectionalIterator2>
inline BidirectionalIterator2 __copy_backward(BidirectionalIterator1 first,
                                              BidirectionalIterator1 last,
                                              BidirectionalIterator2 result) {
  //用迭代器作为循环的控制条件
  while (first != last) *--result = *--last;
  return result;
}


template <class BidirectionalIterator1, class BidirectionalIterator2>
struct __copy_backward_dispatch
{
  BidirectionalIterator2 operator()(BidirectionalIterator1 first,
                                    BidirectionalIterator1 last,
                                    BidirectionalIterator2 result) {
    //调用__copy_backward依次复制
    return __copy_backward(first, last, result);
  }
};

#ifdef __STL_CLASS_PARTIAL_SPECIALIZATION

template <class T>
inline T* __copy_backward_t(const T* first, const T* last, T* result,
                            __true_type) {
  const ptrdiff_t N = last - first;
  //内存直接复制
  memmove(result - N, first, sizeof(T) * N);
  return result - N;
}

template <class T>
inline T* __copy_backward_t(const T* first, const T* last, T* result,
                            __false_type) {
  //调用__copy_backward依次复制
  return __copy_backward(first, last, result);
}
//__copy_backward_dispatch特化版本1
template <class T>
struct __copy_backward_dispatch<T*, T*>
{
  T* operator()(T* first, T* last, T* result) {
    //判断是否有trivial_assignment_operator
    //根据这个条件选择合适的算法
    typedef typename __type_traits<T>::has_trivial_assignment_operator t;
    return __copy_backward_t(first, last, result, t());
  }
};
__copy_backward_dispatch特化版本2
template <class T>
struct __copy_backward_dispatch<const T*, T*>
{
  T* operator()(const T* first, const T* last, T* result) {
    typedef typename __type_traits<T>::has_trivial_assignment_operator t;
    return __copy_backward_t(first, last, result, t());
  }
};
#endif /* __STL_CLASS_PARTIAL_SPECIALIZATION */

template <class BidirectionalIterator1, class BidirectionalIterator2>
inline BidirectionalIterator2 copy_backward(BidirectionalIterator1 first,
                                            BidirectionalIterator1 last,
                                            BidirectionalIterator2 result) {
  return __copy_backward_dispatch<BidirectionalIterator1,
                                  BidirectionalIterator2>()(first, last,
                                                            result);
}
fill&&fill_n

这个函数的作用是将一个区间内的值全部设置为value,算法的思想也很简单,就是依次赋值

template <class ForwardIterator, class T>
void fill(ForwardIterator first, ForwardIterator last, const T& value) {
  for ( ; first != last; ++first)
    *first = value;
}

template <class OutputIterator, class Size, class T>
OutputIterator fill_n(OutputIterator first, Size n, const T& value) {
  for ( ; n > 0; --n, ++first)
    *first = value;
  return first;
}
mismatch

该函数的作用是比较[first1, last1)以及[first2, first2 + (last1 - first1))之间的元素.

  • 若相等或者没有到last1,则继续;
  • 否则返回pair,分别指向这两个序列之间第一个互不相等的元素或者last1以及first2 + (last1 - first1)。
//版本1
template <class InputIterator1, class InputIterator2>
pair<InputIterator1, InputIterator2> mismatch(InputIterator1 first1,
                                              InputIterator1 last1,
                                              InputIterator2 first2) {
  while (first1 != last1 && *first1 == *first2) {
    ++first1;
    ++first2;
  }
  return pair<InputIterator1, InputIterator2>(first1, first2);
}
//版本2
//可从外界传入binary_pred
template <class InputIterator1, class InputIterator2, class BinaryPredicate>
pair<InputIterator1, InputIterator2> mismatch(InputIterator1 first1,
                                              InputIterator1 last1,
                                              InputIterator2 first2,
                                              BinaryPredicate binary_pred) {
  while (first1 != last1 && binary_pred(*first1, *first2)) {
    ++first1;
    ++first2;
  }
  return pair<InputIterator1, InputIterator2>(first1, first2);
}
equal

判断两个序列在一个范围内是否相等

//版本1
template <class InputIterator1, class InputIterator2>
inline bool equal(InputIterator1 first1, InputIterator1 last1,
                  InputIterator2 first2) {
  //依次比较,只要不相等就返回false
  for ( ; first1 != last1; ++first1, ++first2)
    if (*first1 != *first2)
      return false;
  return true;
}
//版本2
//可从外界传入binary_pred
template <class InputIterator1, class InputIterator2, class BinaryPredicate>
inline bool equal(InputIterator1 first1, InputIterator1 last1,
                  InputIterator2 first2, BinaryPredicate binary_pred) {
  for ( ; first1 != last1; ++first1, ++first2)
    if (!binary_pred(*first1, *first2))
      return false;
  return true;
}

lexicographical_compare

这个函数依次比较两个序列 [first1, last1),[first2, last2)。比较的结果有两种true,false
依次比较两个序列,循环结束前

  • 如果出现*first1 < *first2,则返回true
  • 如果出现*first2 < *first1,则返回false

如果直到循环结束,两个序列的值都相等

  • 如果第一个序列比第二个序列短,则返回true
  • 否则返回false(两个序列长度相等也返回false)
//版本1
template <class InputIterator1, class InputIterator2>
bool lexicographical_compare(InputIterator1 first1, InputIterator1 last1,
                             InputIterator2 first2, InputIterator2 last2) {
  for ( ; first1 != last1 && first2 != last2; ++first1, ++first2) {
    if (*first1 < *first2)
      return true;
    if (*first2 < *first1)
      return false;
  }
  return first1 == last1 && first2 != last2;
}
//版本2
//可从外界传入比较器
template <class InputIterator1, class InputIterator2, class Compare>
bool lexicographical_compare(InputIterator1 first1, InputIterator1 last1,
                             InputIterator2 first2, InputIterator2 last2,
                             Compare comp) {
  for ( ; first1 != last1 && first2 != last2; ++first1, ++first2) {
    if (comp(*first1, *first2))
      return true;
    if (comp(*first2, *first1))
      return false;
  }
  return first1 == last1 && first2 != last2;
}
//特化版本1 
inline bool
lexicographical_compare(const unsigned char* first1,
                        const unsigned char* last1,
                        const unsigned char* first2,
                        const unsigned char* last2)
{
  const size_t len1 = last1 - first1;
  const size_t len2 = last2 - first2;
  const int result = memcmp(first1, first2, min(len1, len2));
  return result != 0 ? result < 0 : len1 < len2;
}
//特化版本2
inline bool lexicographical_compare(const char* first1, const char* last1,
                                    const char* first2, const char* last2)
{
#if CHAR_MAX == SCHAR_MAX
  return lexicographical_compare((const signed char*) first1,
                                 (const signed char*) last1,
                                 (const signed char*) first2,
                                 (const signed char*) last2);
#else
  return lexicographical_compare((const unsigned char*) first1,
                                 (const unsigned char*) last1,
                                 (const unsigned char*) first2,
                                 (const unsigned char*) last2);
#endif
}

总结

以上我们分析了stl_algobase.h中的一些算法。最值得我们去深究的就是copy算法了,根据不同的情况指定了相应的算法,大大的提高了效率,这种分情况而定的方式在SGISTL中已经不少见了。
接下来我们将继续分析slt_algo.h中的算法。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值