STL区间成员函数及区间算法总结
在这里总结下可替代循环的区间成员函数和区间算法;
相比单元素遍历操作,使用区间成员函数的优势在于:
1)更少的函数调用
2)更少的元素移动
3)更少的内存分配
在区间成员函数不适用的情况下也应该使用区间算法,至少,相比手写循环而言,它更加简单,有效,并且不容易出错;
区间成员函数
区间构造
标准容器都支持区间构造函数:
container::container(InputIteratorbegin,//区间的起点 InputIteratorend);//区间的终点
例如:
intmyints[]={10,20,30,30,20,10,10,20}; std::vector<int>myvector(myints,myints+8);
以上是c++98中常用法,在C++11中,vector可以直接初始化了:
std::vector<int>second={10,20,30,30,20,10,10,20};
或者:
std::vector<int>second({10,20,30,30,20,10,10,20});
区间插入
标准序列容器提供这种形式的insert:
voidcontainer::insert(iteratorposition,//区间插入的位置 InputIteratorbegin,//插入区间的起点 InputIteratorend);//插入区间的终点
例如:
intmyints[]={10,20,30,30,20,10,10,20}; std::vector<int>myvector; myvector.push_back(100); myvector.insert(myvector.begin(),myints,myints+8);//1020303020101020100
关联容器也支持区间插入,但由于其插入后的位置由其比较函数来决定,所以没有区间插入的位置这个参数;
区间删除
标准序列容器提供的erase:
iteratorcontainer::erase(iteratorbegin,iteratorend);
c++98的标准关联容器提供的erase为:
voidcontainer::erase(iteratorbegin,iteratorend);
序列容器调用erase之后,返回一个迭代器(被删除的那个元素的下一个),
而关联容器的erase删除之后并不返回迭代器.【官方解释说如果实现成序列容器那样返回指向下一个迭代器,会导致无法接收的性能下降】;
这一区别在c++11中终于统一了;c++11中,对关联容器调用erase之后会返回一个迭代器(指向被删除元素的下一个);
iteratorcontainer::erase(const_iteratorfirst,const_iteratorlast);
区间赋值
所有标准容器提供了区间赋值的成员函数:
voidcontainer::assign(InputIteratorbegin,InputIteratorend);
这个函数用于给容器赋值,会替代现有值,并根据需要分配空间;
与copy()算法的区别在于它不需要预先分配空间,并有更高的性能;
intmyints[]={10,20,30,40,50,60,70}; std::vector<int>myvector; myvector.assign(myints,myints+7);
通用区间算法
for_each区间迭代
for_each:遍历,对每个元素都执行一个动作;
C++98只支持最原始的for循环,很多语言(java、python等)都实现了foreach区间迭代语法,这让C++程序员眼馋了很久;
在没有foreach区间迭代的时代,我们可以用for_each()算法来代替:
例:对每个元素都加5:
voidmyfunction(int&i){ i+=5; } std::vector<int>myvector; myvector.push_back(10); myvector.push_back(20); myvector.push_back(30); for_each(myvector.begin(),myvector.end(),myfunction);//152535
c++11中新增了区间迭代,使得我们对for_each的依赖降低了,使用也更加方便:
for(auto&i:myvector) { i+=5; }
transform()区间迭代后新值另存为其它地方
对区间中每个元素执行操作后,将修改后的值写入到新区间中;
可以认为这个是for_each()算法不修改原区间的版本;
还是for_each中的例子:
intaddfunction(inti){ returni+5; } voidoutput(inti){ //outputfunction std::cout<<''<<i; } std::vector<int>myvector; myvector.push_back(10); myvector.push_back(20); myvector.push_back(30); std::vector<int>bvector; bvector.resize(myvector.size()); transform(myvector.begin(),myvector.end(),bvector.begin(),addfunction); //输出 for_each(bvector.begin(),bvector.end(),output);//bvector:152535
copy()区间复制
区间复制,一般用于多个容器间的数据传值;
这个算法被用的很普遍,其实,很多使用copy的场景,都可以使用区间成员函数来替代(也建议这么做);
例:复制数组到vector:
intmyints[]={10,20,30,40,50,60,70}; std::vector<int>myvector(7); std::copy(myints,myints+7,myvector.begin());
fill()区间填充
用一个元素来重复填充区间;
这个算法使用频率较低;
例:用5填充vector前4个元素:
std::vector<int>myvector(8); //myvector:00000000 std::fill(myvector.begin(),myvector.begin()+4,5); //myvector:55550000
replace()区间替换
遍历区间,进行值替换:
例:将以下区间中所有20替换为99:
intmyints[]={10,20,30,30,20,10,10,20}; std::vector<int>myvector(myints,myints+8); //1020303020101020 std::replace(myvector.begin(),myvector.end(),20,99);//1099303099101099
更复杂的版本(使用仿函数)replace_if
例:将以下区间中所有大于20替换为99:
boolbigerThen20(inti){returni>20;} intmyints[]={10,20,30,30,20,10,10,20}; std::vector<int>myvector(myints,myints+8); //1020303020101020 std::replace_if(myvector.begin(),myvector.end(),bigerThen20,99);//1020999920101020
由于用到了仿函数,通过replace_if实现的,用for_each()也很容易实现;
remove()区间删除
从区间中删除指定元素;
intmyints[]={10,20,30,30,20,10,10,20}; std::vector<int>myvector(myints,myints+8); //1020303020101020 std::remove(myvector.begin(),myvector.end(),20);//1030301010???
注意,remove并不会真正删除元素,而只是将需要删除的元素放到到最后,同时返回一个新的尾部迭代器,
比如,上述例子中,调用完remove后,vector中的值一般为//1030301010101020
而如果希望真的删除元素,需要加上成员函数erase()来实现删除【remove-erase惯用法】:
myvector.erase(std::remove(myvector.begin(),myvector.end(),20),myvector.end());//1030301010
unique()区间去重
从区间中删除相邻相同的元素,同样,这个算法也不会真正的删除元素,而是将待删除的元素移到区间尾部;
使用【unique-erase惯用法】:
intmyints[]={10,20,20,20,30,30,20,20,10}; //102020203030202010 std::vector<int>myvector(myints,myints+9); std::vector<int>::iteratorit; it=std::unique(myvector.begin(),myvector.end()); //1020302010? ? ? ? myvector.erase(it,myvector.end());
以上所述就是本文的全部内容了,希望大家能够喜欢。