STL区间成员函数及区间算法总结
STL区间成员函数及区间算法总结
在这里总结下可替代循环的区间成员函数和区间算法;
相比单元素遍历操作,使用区间成员函数的优势在于:
1)更少的函数调用
2)更少的元素移动
3)更少的内存分配
在区间成员函数不适用的情况下也应该使用区间算法,至少,相比手写循环而言,它更加简单,有效,并且不容易出错;
区间成员函数
区间构造
标准容器都支持区间构造函数:
container::container(InputIterator begin, // 区间的起点
InputIterator end); // 区间的终点
例如:
int myints[] = { 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:
void container::insert(iterator position, // 区间插入的位置
InputIterator begin, // 插入区间的起点
InputIterator end); // 插入区间的终点
例如:
int myints[] = { 10, 20, 30, 30, 20, 10, 10, 20 };
std::vector<int> myvector;
myvector.push_back(100);
myvector.insert(myvector.begin(),myints,myints+8); //10 20 30 30 20 10 10 20 100
关联容器也支持区间插入,但由于其插入后的位置由其比较函数来决定,所以没有区间插入的位置这个参数;
区间删除
标准序列容器提供的erase:
iterator container::erase(iterator begin, iterator end);
c++98的标准关联容器提供的erase为:
void container::erase(iterator begin, iterator end);
序列容器调用erase之后,返回一个迭代器(被删除的那个元素的下一个),
而关联容器的erase删除之后并不返回迭代器.【官方解释说如果实现成序列容器那样返回指向下一个迭代器,会导致无法接收的性能下降】;
这一区别在c++11中终于统一了;c++11中,对关联容器调用erase之后会返回一个迭代器(指向被删除元素的下一个);
iterator container::erase(const_iterator first, const_iterator last);
区间赋值
所有标准容器提供了区间赋值的成员函数:
void container::assign(InputIterator begin, InputIterator end);
这个函数用于给容器赋值,会替代现有值,并根据需要分配空间;
与copy()算法的区别在于它不需要预先分配空间,并有更高的性能;
int myints[]={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:
void myfunction (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); //15 25 35
c++11中新增了区间迭代,使得我们对for_each的依赖降低了,使用也更加方便:
for(auto &i : myvector )
{
i+=5;
}
transform() 区间迭代后新值另存为其它地方
对区间中每个元素执行操作后,将修改后的值写入到新区间中;
可以认为这个是for_each()算法不修改原区间的版本;
还是for_each中的例子:
int addfunction(int i ){
return i+5;
}
void output (int i) { // output function
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: 15 25 35
copy() 区间复制
区间复制,一般用于多个容器间的数据传值;
这个算法被用的很普遍,其实,很多使用copy的场景,都可以使用区间成员函数来替代(也建议这么做);
例:复制数组到vector:
int myints[]={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: 0 0 0 0 0 0 0 0
std::fill (myvector.begin(),myvector.begin()+4,5); // myvector: 5 5 5 5 0 0 0 0
replace() 区间替换
遍历区间,进行值替换:
例:将以下区间中所有20替换为99:
int myints[] = { 10, 20, 30, 30, 20, 10, 10, 20 };
std::vector<int> myvector (myints, myints+8); // 10 20 30 30 20 10 10 20
std::replace (myvector.begin(), myvector.end(), 20, 99); // 10 99 30 30 99 10 10 99
更复杂的版本(使用仿函数)replace_if
例:将以下区间中所有大于20替换为99:
bool bigerThen20 (int i) { return i > 20; }
int myints[] = { 10, 20, 30, 30, 20, 10, 10, 20 };
std::vector<int> myvector (myints, myints+8); // 10 20 30 30 20 10 10 20
std::replace_if (myvector.begin(), myvector.end(), bigerThen20, 99); //10 20 99 99 20 10 10 20
由于用到了仿函数,通过replace_if实现的,用for_each()也很容易实现;
remove() 区间删除
从区间中删除指定元素;
int myints[] = { 10, 20, 30, 30, 20, 10, 10, 20 };
std::vector<int> myvector (myints, myints+8); // 10 20 30 30 20 10 10 20
std::remove(myvector.begin(), myvector.end(), 20); // 10 30 30 10 10 ? ? ?
注意,remove并不会真正删除元素,而只是将需要删除的元素放到到最后,同时返回一个新的尾部迭代器,
比如,上述例子中,调用完remove后,vector中的值一般为 //10 30 30 10 10 10 10 20
而如果希望真的删除元素,需要加上成员函数erase()来实现删除 【remove-erase惯用法】:
myvector.erase(std::remove(myvector.begin(), myvector.end(), 20),myvector.end()); // 10 30 30 10 10
unique() 区间去重
从区间中删除相邻相同的元素,同样,这个算法也不会真正的删除元素,而是将待删除的元素移到区间尾部;
使用【unique-erase惯用法】:
int myints[] = {10,20,20,20,30,30,20,20,10}; // 10 20 20 20 30 30 20 20 10
std::vector<int> myvector (myints,myints+9);
std::vector<int>::iterator it;
it = std::unique (myvector.begin(), myvector.end()); // 10 20 30 20 10 ? ? ? ?
myvector.erase(it,myvector.end());
Posted by: 大CC | 28JUN,2015
博客:blog.me115.com [订阅]
微博:新浪微博
STL区间成员函数及区间算法总结的更多相关文章
- STL进阶--成员函数 vs 算法
容器的成员函数 vs 算法 容器中同名的函数 List: void remove(const T); template<class Comp> void remove_if(Comp); ...
- STL容器 成员函数 时间复杂度表
Sequence containers Associative containers Headers <vector> <deque> <list> <s ...
- 成员函数指针与高性能C++委托
1 引子 标准C++中没有真正的面向对象的函数指针.这一点对C++来说是不幸的,因为面向对象的指针(也叫做“闭包(closure)”或“委托(delegate)”)在一些语言中已经证明了它宝贵的价值. ...
- [转]成员函数指针与高性能的C++委托
原文(作者:Don Clugston):Member Function Pointers and the Fastest Possible C++ Delegates 译文(作者:周翔): 成员函数指 ...
- C++STL(vector,map,set,list)成员函数整理
/ *最近ACM比赛,用到的时候忘记成员函数了,贼尴尬,给以后比赛做下准备 */ LIST: 构造函数 list<int> c0; //空链表 list<int> c1(3); ...
- C++STL(vector,map,set,list,bitset,deque)成员函数整理
补充: vector 删除指定元素: vec.erase(remove(vec.begin(), vec.end(), val), vec.end());remove()返回的是删 ...
- c++ stl容器set成员函数介绍及set集合插入,遍历等用法举例
c++ stl集合set介绍 c++ stl集合(Set)是一种包含已排序对象的关联容器.set/multiset会根据待定的排序准则,自动将元素排序.两者不同在于前者不允许元素重复,而后者允许. 1 ...
- c++ STL stack容器成员函数
这是后进先出的栈,成员函数比较简单,因为只能操作栈顶的元素.不提供清除什么的函数. 函数 描述 bool s.empty() 栈是否为空(即size=0).若空,返回true,否则,false. vo ...
- STL之list函数解析
STL之list函数解析 list是C++标准模版库(STL,Standard Template Library)中的部分内容.实际上,list容器就是一个双向链表,可以高效地进行插入删除元素. 使用 ...
随机推荐
- 精通 JS正则表达式
一.正则表达式可以: 测试字符串的某个模式.例如,可以对一个输入字符串进行测试,看在该字符串是否存在一个电话号码模式或一个信用卡号码模式.这称为数据有效性验证 替换文本.可以在文档中使用一个正则表达式 ...
- Java中类方法与实例方法的区别
实例方法可以对当前对象的实例变量进行操作,也可以对类变量进行操作,但类方法不能访问实例变量.实例方法必须由实例对象来调用,而类方法除了可由实例对象调用外,还可以由类名直接调用. 另外,在类方法中不能使 ...
- php获取目录中的所有文件名
<?php /** * [php获取目录中的所有文件名] */ //1.先打开要操作的目录,并用一个变量指向它 //打开当前目录下的目录pic下的子目录common. $handler = op ...
- java对象equals方法的重写
根类Object中的equals方法描述: public boolean equals(Object obj)The equals method for class Object implements ...
- opencv通过dll调用matlab函数,图片作为参数
[blog 项目实战派]opencv通过dll调用matlab函数,图片作为参数 前文介绍了如何“csharp通过dll调用opencv函数,图片作为参数”.而在实 ...
- 越狱后如何添加cydia源及cydia源大全
http://jingyan.baidu.com/article/6c67b1d6cc53fe2787bb1e06.html 软件游戏能PJ,插件其实也一样,所以有些源里面就包含了大量的PJ插件~ a ...
- hnu Dirichlet's Theorem
/* 求ax+b x属于区间[L,R];范围内素数的个数. a*R+b<=10^12 ; R-L+1<=10^6 枚举,超时. 1.如果GCD(a,b)>1 那么a+b 2*a+b ...
- qbxt十一系列三
[题目分析] 这完全是个数学题啊,有些崩溃,上午考试写了两个小时,20分,于是乎 下午改啊改啊 改到10分....如果第二个圆的圆心在第一个圆.....呃 说不清楚 像下面这个图这样,两圆重叠部分中C ...
- Java中HashMap遍历的两种方式
Java中HashMap遍历的两种方式 转]Java中HashMap遍历的两种方式原文地址: http://www.javaweb.cc/language/java/032291.shtml 第一种: ...
- Struts2的输入校验(1)——校验规则文件的编写
Struts2的输入校验(1) --校验规则文件的编写 Struts2提供了基于验证框架的输入校验,所有的输入校验只要编写配置文件,Struts2的验证框架将会负责进行服务器校验和客户端校验. 注: ...