• STL源代码分析——STL算法remove删除算法


    前言

        因为在前文的《STL算法剖析》中,源代码剖析许多。不方便学习,也不方便以后复习,这里把这些算法进行归类。对他们单独的源代码剖析进行解说。本文介绍的STL算法中的remove删除算法。源代码中介绍了函数removeremove_copyremove_ifremove_copy_ifuniqueunique_copy

    并对这些函数的源代码进行具体的剖析。并适当给出使用样例,具体详见以下源代码剖析。

    remove移除算法源代码剖析

    // remove, remove_if, remove_copy, remove_copy_if
    
    //移除[first,last)区间内全部与value值相等的元素,并非真正的从容器中删除这些元素(原容器的内容不会改变)
    //而是将结果拷贝到一个以result为起始位置的容器中。新容器能够与原容器重叠
    template <class _InputIter, class _OutputIter, class _Tp>
    _OutputIter remove_copy(_InputIter __first, _InputIter __last,
                            _OutputIter __result, const _Tp& __value) {
      __STL_REQUIRES(_InputIter, _InputIterator);
      __STL_REQUIRES(_OutputIter, _OutputIterator);
      __STL_REQUIRES_BINARY_OP(_OP_EQUAL, bool,
           typename iterator_traits<_InputIter>::value_type, _Tp);
      for ( ; __first != __last; ++__first)//遍历容器
        if (!(*__first == __value)) {//假设不相等
          *__result = *__first;//赋值给新容器
          ++__result;//新容器前进一个位置
        }
      return __result;
    }
    //移除[first,last)区间内被仿函数pred推断为true的元素,并非真正的从容器中删除这些元素(原容器的内容不会改变)
    //而是将结果拷贝到一个以result为起始位置的容器中。新容器能够与原容器重叠
    template <class _InputIter, class _OutputIter, class _Predicate>
    _OutputIter remove_copy_if(_InputIter __first, _InputIter __last,
                               _OutputIter __result, _Predicate __pred) {
      __STL_REQUIRES(_InputIter, _InputIterator);
      __STL_REQUIRES(_OutputIter, _OutputIterator);
      __STL_UNARY_FUNCTION_CHECK(_Predicate, bool,
                 typename iterator_traits<_InputIter>::value_type);
      for ( ; __first != __last; ++__first)//遍历容器
        if (!__pred(*__first)) {//若pred推断为false
          *__result = *__first;//赋值给新容器
          ++__result;//新容器前进一个位置
        }
      return __result;
    }
    //移除[first,last)区间内全部与value值相等的元素,该操作不会改变容器大小。仅仅是容器中元素值改变
    //即移除之后,又一次整理容器的内容
    template <class _ForwardIter, class _Tp>
    _ForwardIter remove(_ForwardIter __first, _ForwardIter __last,
                        const _Tp& __value) {
      __STL_REQUIRES(_ForwardIter, _Mutable_ForwardIterator);
      __STL_REQUIRES_BINARY_OP(_OP_EQUAL, bool,
           typename iterator_traits<_ForwardIter>::value_type, _Tp);
      __STL_CONVERTIBLE(_Tp, typename iterator_traits<_ForwardIter>::value_type);
      __first = find(__first, __last, __value);//利用顺序查找找出第一个与value相等的元素
      _ForwardIter __i = __first;
      //以下调用remove_copy
      return __first == __last ? __first 
                               : remove_copy(++__i, __last, __first, __value);
    }
    //移除[first,last)区间内全部被pred推断为true的元素,该操作不会改变容器大小,仅仅是容器中元素值改变
    //即移除之后,又一次整理容器的内容
    template <class _ForwardIter, class _Predicate>
    _ForwardIter remove_if(_ForwardIter __first, _ForwardIter __last,
                           _Predicate __pred) {
      __STL_REQUIRES(_ForwardIter, _Mutable_ForwardIterator);
      __STL_UNARY_FUNCTION_CHECK(_Predicate, bool,
                   typename iterator_traits<_ForwardIter>::value_type);
      __first = find_if(__first, __last, __pred);//利用顺序查找找出第一个与value相等的元素
      _ForwardIter __i = __first;
      //以下调用remove_copy_if
      return __first == __last ? __first 
                               : remove_copy_if(++__i, __last, __first, __pred);
    }
    //上面四个移除函数举例:
    /*
    	#include <iostream>     // std::cout
    	#include <algorithm>    // std::remove
    
    	bool IsOdd (int i) { return ((i%2)==1); }
    
    	int main () {
    	  int myints[] = {10,20,31,30,20,11,10,20};      // 10 20 31 30 20 11 10 20
    
    	  std::vector<int> myvector (8);
    	  std::remove_copy (myints,myints+8,myvector.begin(),20); // 10 31 30 11 10 0 0 0
    	  std::cout << "myvector contains:";
    	  for (std::vector<int>::iterator it=myvector.begin(); it!=myvector.end(); ++it)
    		std::cout << ' ' << *it;
    	  std::cout << '
    ';
      
    	  // bounds of range:
    	  int* pbegin = myints;                          // ^
    	  int* pend = myints+sizeof(myints)/sizeof(int); // ^                       ^
    	  pend = std::remove (pbegin, pend, 20);         // 10 31 30 11 10 ?  ?  ?
    													 // ^              ^
    	  std::cout << "range contains:";
    	  for (int* p=pbegin; p!=pend; ++p)
    		std::cout << ' ' << *p;
    	  std::cout << '
    ';
      
    	  std::vector<int> myvector2 (7);
    	  std::remove_copy_if (myints,myints+7,myvector2.begin(),IsOdd);
    	  std::cout << "myvector2 contains:";
    	  for (std::vector<int>::iterator it=myvector2.begin(); it!=myvector2.end(); ++it)
    		std::cout << ' ' << *it;
    	  std::cout << '
    ';
      
    	  pend = std::remove_if (pbegin, pend, IsOdd);   // 10 30 10 ? ?

    ? ? ?

    // ^ ^ std::cout << "the range contains:"; for (int* p=pbegin; p!=pend; ++p) std::cout << ' ' << *p; std::cout << ' '; return 0; } Output: myvector contains: 10 31 30 11 10 0 0 0 range contains: 10 31 30 11 10 myvector2 contains: 10 30 10 10 0 0 0 the range contains: 10 30 10 */ // unique and unique_copy template <class _InputIter, class _OutputIter, class _Tp> _OutputIter __unique_copy(_InputIter __first, _InputIter __last, _OutputIter __result, _Tp*) { _Tp __value = *__first; *__result = __value; while (++__first != __last) if (!(__value == *__first)) { __value = *__first; *++__result = __value; } return ++__result; } //若result类型为output_iterator_tag,则调用该函数 template <class _InputIter, class _OutputIter> inline _OutputIter __unique_copy(_InputIter __first, _InputIter __last, _OutputIter __result, output_iterator_tag) { //推断first的value_type类型,依据不同类型调用不同函数 return __unique_copy(__first, __last, __result, __VALUE_TYPE(__first)); } //若result类型为forward_iterator_tag,则调用该函数 template <class _InputIter, class _ForwardIter> _ForwardIter __unique_copy(_InputIter __first, _InputIter __last, _ForwardIter __result, forward_iterator_tag) { *__result = *__first;//记录第一个元素 while (++__first != __last)//遍历区间 //若不存在相邻反复元素,则继续记录到目标区result if (!(*__result == *__first)) *++__result = *__first;//记录元素到目标区 return ++__result; } ////unique_copy将区间[first,last)内元素拷贝到以result开头的区间上,可是假设存在相邻反复元素时,仅仅复制当中第一个元素 //和unique一样。这里也有两个版本号 /* 函数原型: equality (1) template <class InputIterator, class OutputIterator> OutputIterator unique_copy (InputIterator first, InputIterator last, OutputIterator result); predicate (2) template <class InputIterator, class OutputIterator, class BinaryPredicate> OutputIterator unique_copy (InputIterator first, InputIterator last, OutputIterator result, BinaryPredicate pred); */ //版本号一 template <class _InputIter, class _OutputIter> inline _OutputIter unique_copy(_InputIter __first, _InputIter __last, _OutputIter __result) { __STL_REQUIRES(_InputIter, _InputIterator); __STL_REQUIRES(_OutputIter, _OutputIterator); __STL_REQUIRES(typename iterator_traits<_InputIter>::value_type, _EqualityComparable); if (__first == __last) return __result; //依据result迭代器的类型,调用不同的函数 return __unique_copy(__first, __last, __result, __ITERATOR_CATEGORY(__result)); } template <class _InputIter, class _OutputIter, class _BinaryPredicate, class _Tp> _OutputIter __unique_copy(_InputIter __first, _InputIter __last, _OutputIter __result, _BinaryPredicate __binary_pred, _Tp*) { __STL_BINARY_FUNCTION_CHECK(_BinaryPredicate, bool, _Tp, _Tp); _Tp __value = *__first; *__result = __value; while (++__first != __last) if (!__binary_pred(__value, *__first)) { __value = *__first; *++__result = __value; } return ++__result; } template <class _InputIter, class _OutputIter, class _BinaryPredicate> inline _OutputIter __unique_copy(_InputIter __first, _InputIter __last, _OutputIter __result, _BinaryPredicate __binary_pred, output_iterator_tag) { return __unique_copy(__first, __last, __result, __binary_pred, __VALUE_TYPE(__first)); } template <class _InputIter, class _ForwardIter, class _BinaryPredicate> _ForwardIter __unique_copy(_InputIter __first, _InputIter __last, _ForwardIter __result, _BinaryPredicate __binary_pred, forward_iterator_tag) { __STL_BINARY_FUNCTION_CHECK(_BinaryPredicate, bool, typename iterator_traits<_ForwardIter>::value_type, typename iterator_traits<_InputIter>::value_type); *__result = *__first; while (++__first != __last) if (!__binary_pred(*__result, *__first)) *++__result = *__first; return ++__result; } //版本号二 template <class _InputIter, class _OutputIter, class _BinaryPredicate> inline _OutputIter unique_copy(_InputIter __first, _InputIter __last, _OutputIter __result, _BinaryPredicate __binary_pred) { __STL_REQUIRES(_InputIter, _InputIterator); __STL_REQUIRES(_OutputIter, _OutputIterator); if (__first == __last) return __result; //依据result迭代器的类型,调用不同的函数 return __unique_copy(__first, __last, __result, __binary_pred, __ITERATOR_CATEGORY(__result)); } //移除区间[first,last)相邻连续反复的元素 //unique有两个版本号 //功能:Removes all but the first element from every consecutive group of equivalent elements in the range [first,last). /* 函数原型: equality (1):版本号一採用operator== template <class ForwardIterator> ForwardIterator unique (ForwardIterator first, ForwardIterator last); predicate (2):版本号二採用pred操作 template <class ForwardIterator, class BinaryPredicate> ForwardIterator unique (ForwardIterator first, ForwardIterator last, BinaryPredicate pred); */ //版本号一 template <class _ForwardIter> _ForwardIter unique(_ForwardIter __first, _ForwardIter __last) { __STL_REQUIRES(_ForwardIter, _Mutable_ForwardIterator); __STL_REQUIRES(typename iterator_traits<_ForwardIter>::value_type, _EqualityComparable); __first = adjacent_find(__first, __last);//找出第一个相邻元素的起始位置 return unique_copy(__first, __last, __first);//调用unique_copy完毕操作 } //版本号二 template <class _ForwardIter, class _BinaryPredicate> _ForwardIter unique(_ForwardIter __first, _ForwardIter __last, _BinaryPredicate __binary_pred) { __STL_REQUIRES(_ForwardIter, _Mutable_ForwardIterator); __STL_BINARY_FUNCTION_CHECK(_BinaryPredicate, bool, typename iterator_traits<_ForwardIter>::value_type, typename iterator_traits<_ForwardIter>::value_type); __first = adjacent_find(__first, __last, __binary_pred);//找出第一个相邻元素的起始位置 return unique_copy(__first, __last, __first, __binary_pred);//调用unique_copy完成操作 }


    参考资料:

    《STL源代码分析》侯杰

  • 相关阅读:
    Mysql之锁、事务绝版详解干货!
    SSL基础知识(比较清楚)
    数字证书使用流程指南
    HTTPS与SSL
    IIS 6.0 Web园(Web Garden)
    验证数字可以有千分符可以有0个1个小数点小数点后输入后四舍五入保留两位(写个js验证真费劲)
    线程安全
    利用SSL给IIS加把锁(转)
    弹出div后其它不能操作(小技巧)
    关于反射
  • 原文地址:https://www.cnblogs.com/zfyouxi/p/5042384.html
Copyright © 2020-2023  润新知