c++ STL替换算法:replace()、replace_if()、replace_copy()、replace_copy_if()详解_替换算法

主要函数有:

  • replace():用一个给定值替换一些值。
  • replace_if():替换满足谓词的一些元素。
  • replace_copy():复制序列时用一给定值替换元素。
  • replace_copy_if():复制序列时替换满足谓词的元素。

replace函数模板的行为等同于:

template <class ForwardIterator, class T>
  void replace (ForwardIterator first, ForwardIterator last,
                const T& old_value, const T& new_value)
{
  while (first!=last) {
    if (*first == old_value) *first=new_value;
    ++first;
  }
}

前两个参数是被处理序列的前向迭代器,第 3 个参数是被替换的值,第 4 个参数是新的值。遍历容器序列,若某元素等于旧值,则用新值代替。

例子:

#include <iostream>
#include <iterator>
#include <vector>
#include <algorithm>
using namespace std;
int main(){
    int a[9] = {1, 2, 3, 4, 5, 4, 3, 2, 1};
    cout<< "原始数据: ";
    copy(a, a + 9, ostream_iterator<int>(cout, " "));
    cout<< endl;
    
    cout<< "原数据2用10代替(replace): ";
    vector<int> v1(a, a + 9);
    replace(v1.begin(), v1.end(), 2, 10);
    copy(v1.begin(), v1.end(), ostream_iterator<int>(cout, " "));
    cout<< endl;
}

c++ STL替换算法:replace()、replace_if()、replace_copy()、replace_copy_if()详解_算法_02

replace_if函数模板的行为等同于:

template < class ForwardIterator, class UnaryPredicate, class T >
  void replace_if (ForwardIterator first, ForwardIterator last,
                   UnaryPredicate pred, const T& new_value)
{
  while (first!=last) {
    if (pred(*first)) *first=new_value;
    ++first;
  }
}

其中第 3 个参数是一个谓词,第 4 个参数是新的值。参数的类型一般是元素类型的 const 引用;const 不是强制性的,但谓词不应该改变元素。

例子:

#include <iostream>
#include <iterator>
#include <vector>
#include <algorithm>
using namespace std;
int main(){
    int a[9] = {1, 2, 3, 4, 5, 4, 3, 2, 1};
    cout<< "原始数据: ";
    copy(a, a + 9, ostream_iterator<int>(cout, " "));
    cout<< endl;
    
    cout<< "原数据<4用20代替(replace_if): ";
    vector<int> v1(a, a + 9);
    replace_if(v1.begin(), v1.end(), bind2nd(less<int>(), 4), 20);
    copy(v1.begin(), v1.end(), ostream_iterator<int>(cout, " "));
    cout<< endl;
}

c++ STL替换算法:replace()、replace_if()、replace_copy()、replace_copy_if()详解_替换算法_03

replace_copy函数模板的行为等同于:

template <class InputIterator, class OutputIterator, class T>
  OutputIterator replace_copy (InputIterator first, InputIterator last,
                               OutputIterator result, const T& old_value, const T& new_value)
{
  while (first!=last) {
    *result = (*first==old_value)? new_value: *first;
    ++first; ++result;
  }
  return result;
}

replace_copy() 算法和 replace() 做的事是一样的,但它的结果会被保存到另一个序列中,而不会改变原始序列。它的前两个参数是输入序列的正向迭代器,第 3 个参数是输入序列的开始迭代器,最后两个参数分别是要被替换的值和替换值。

例子:

#include <iostream>
#include <iterator>
#include <vector>
#include <algorithm>
using namespace std;
int main(){
    int a[9] = {1, 2, 3, 4, 5, 4, 3, 2, 1};
    cout<< "原始数据: ";
    copy(a, a + 9, ostream_iterator<int>(cout, " "));
    cout<< endl;
    
    cout<< "原数据4用30代替(replace_copy): ";
    vector<int> v1(a, a + 9);
    vector<int> v2;
    replace_copy(v1.begin(), v1.end(), back_inserter(v2), 4, 30);
    copy(v2.begin(), v2.end(), ostream_iterator<int>(cout, " "));
    cout<< endl;
}

c++ STL替换算法:replace()、replace_if()、replace_copy()、replace_copy_if()详解_替换算法_04

replace_copy_if函数模板的行为等同于:

template <class InputIterator, class OutputIterator, class UnaryPredicate, class T>
  OutputIterator replace_copy_if (InputIterator first, InputIterator last,
                                  OutputIterator result, UnaryPredicate pred,
                                  const T& new_value)
{
  while (first!=last) {
    *result = (pred(*first))? new_value: *first;
    ++first; ++result;
  }
  return result;
}

当然replace_copy_if() 和 replace_if() 算法是相同的,但它的结果会被保存到另一个序列中。它的前两个参数是输入序列的迭代器,第 3 个参数是输出序列的开始迭代器,最后两个参数分别是谓词和替换值。

例子:

#include <iostream>
#include <iterator>
#include <vector>
#include <algorithm>
using namespace std;
int main(){
    int a[9] = {1, 2, 3, 4, 5, 4, 3, 2, 1};
    cout<< "原始数据: ";
    copy(a, a + 9, ostream_iterator<int>(cout, " "));
    cout<< endl;
    
    cout<< "原数据<4用40代替(replace_copy_if): ";
    vector<int> v1(a, a + 9);
    vector<int> v2;
    replace_copy_if(v1.begin(), v1.end(), back_inserter(v2), bind2nd(less<int>(), 4), 30);
    copy(v2.begin(), v2.end(), ostream_iterator<int>(cout, " "));
    cout<< endl;
}

c++ STL替换算法:replace()、replace_if()、replace_copy()、replace_copy_if()详解_替换算法_05

一个replace易犯的一个错误:

#include <iostream>
#include <iterator>
#include <algorithm>
using namespace std;
int main(){
    int a[] = {2, 1, 3, 2, 2, 5};
    cout<< "原始数据: ";
    copy(a, a + 6, ostream_iterator<int>(cout, " "));
    cout<< endl;
    
    replace(a, a + 6, a[0], 10);
    copy(a, a + 6, ostream_iterator<int>(cout, " "));
    cout<< endl;
}

c++ STL替换算法:replace()、replace_if()、replace_copy()、replace_copy_if()详解_替换算法_06

这看起来是一个非常简单的例子,完成的功能是把数组a[]中所有整型数2用10来代替。但结果却是“10 1 3 2 2 5”,仅第一个2变成了10,这是什么原因呢?

看一下replace的定义,就能容易发现原因:

void replace (Fwdit first,FwdIt last,const T & vold,const T & vnew)

vold参数是引用调用,而非传值调用。对本例而言,初始时vold=2,按表意形式相当于replace(a,a+6,2,10),但当第一次发现数组中元素⒉,恰好是a[0],这样a[o]就变成10。由于是引用调用,相当于vold=10,这样当继续扫描数组a时,按表意形式相当于replace(a+1,a+6,10,10),因为 vold=vnew=10,所以α数组后续元素不可能再发生变化。