参考文档:http://www.cnblogs.com/wang7/archive/2012/04/27/2474138.html
http://blog.csdn.net/ls306196689/article/details/35787955
std::vector是我在标准库中实用最频繁的容器。总结一下在遍历和创建vector时需要注意的一些地方。
在不考虑线程安全问题的前提下,在C++11中有五种遍历方式。
方式一
for (size_t i =0; i < vec.size(); i ++) {
int d = vec[i];
}
方式二
size_t len = vec.size();
for (size_t i =0; i < len; i ++) {
int d = vec[i];
}
方式三
for (auto it = vec.begin(); it != vec.end(); it ++) {
int d = *it;
}
方式四
for (int i:vec) {
int d = i;
}
方式五
for_each(vec.begin(), vec.end(), [](int i){
int d = i;
});
代码很简单,如果不实际测试的话。你能推测出哪种方式效率最高吗?
我在mac下面用xcode测试了这五种遍历方式。
////h文件
void testBianli();
void testBianli1(conststd::vector<int>& vec);
void testBianli2(conststd::vector<int>& vec);
void testBianli3(conststd::vector<int>& vec);
void testBianli4(const std::vector<int>& vec);
void testBianli5(const std::vector<int>& vec);
////end h文件
///cpp文件
void testBianli()
{
size_t counter = 1000000;
std::vector<int> vec(counter);
testBianli1(vec);
testBianli2(vec);
testBianli3(vec);
testBianli4(vec);
testBianli5(vec);
}
void testBianli1(conststd::vector<int>& vec)
{
MEARSURE_DURATION(all);
for (size_t i =0; i < vec.size(); i ++) {
int d = vec[i];
}
}
void testBianli2(conststd::vector<int>& vec)
{
MEARSURE_DURATION(all);
size_t len = vec.size();
for (size_t i =0; i < len; i ++) {
int d = vec[i];
}
}
void testBianli3(conststd::vector<int>& vec)
{
MEARSURE_DURATION(all);
for (auto it = vec.begin(); it != vec.end(); it ++) {
int d = *it;
}
}
void testBianli4(conststd::vector<int>& vec)
{
MEARSURE_DURATION(all);
for (int i:vec) {
int d = i;
}
}
void testBianli5(conststd::vector<int>& vec)
{
MEARSURE_DURATION(all);
for_each(vec.begin(), vec.end(), [](int i){
int d = i;
});
}
其中需要定义一个测试函数运行时间的类和一个宏
#define MEARSURE_DURATION(fun) CFunctionDuration fun(std::string(std::string(__FUNCTION__) +" " +std::string(#fun)).c_str() );
class CFunctionDuration {
public:
CFunctionDuration(const char* funname)
{
m_start_df = clock();
sprintf(m_funname,"%s",funname);
}
~CFunctionDuration()
{
double du = (clock() -m_start_df)*0.001;
if (du >= 0) {
printf("%s running duration:%f(ms) ",m_funname,du);
}
}
private:
double m_start_df;
char m_funname[256];
};
最后输出结果如下:
testBianli1 all running duration:3.440000(ms)
testBianli2 all running duration:2.854000(ms)
testBianli3 all running duration:11.009000(ms)
testBianli4 all running duration:5.109000(ms)
testBianli5 all running duration:7.637000(ms)
很明显了,第二种方式是最快的。个人觉得原因如下:
第一种方法每次都要调用size()函数去计算vec的长度。通过查看size(),其实现如下:
_LIBCPP_INLINE_VISIBILITY
size_type size() const_NOEXCEPT
{return static_cast<size_type>(this->__end_ -this->__begin_);}
指针地址相减,再来一个强制转换最后得到size()。就这这里稍微费点时间。
第三种方式是最费时间的。使用迭代器it循环,迭代器本身不是内部数据,它的各种操作(比较,偏移,取值操作)都是一系列内联函数操作,暗地里干的事远比看到的复杂。这个迭代器给自己套上伪装,让你可以像使用指针一样利用它去访问对象,但是毕竟中间隔了一层。个人觉得迭代器的实用主要是便于stl中算法的实现,有一种通用的数据类型来访问各种容器中的元素。
第四种方式从形式上看非常简洁,可干活却没有长相利索。这是C++11的新特性。这篇博文中有详细介绍http://www.cnblogs.com/h46incon/archive/2013/06/02/3113737.html.
第五种方式也是c++的新特性。其中包括大受推崇的lambda特性。这种特性是向其它语言学习的结果。在这里也跑的不是最快的。
其实这些运行时间结果的差别也只有在遍历过程中对元素操作的过程很简短的时候才会显现出来。当对每个元素操作花费的时间跟纯粹遍历vector所费时间不是一个数量级时,这些区别就不重要了。另外这个时间在不同设备上运行的时间肯定是不一样的。不同编译器下得到的结果也不一样,但是其相对运行效率还是有参考意义的。
1 基本操作
(1)头文件#include<vector>.
(2)创建vector对象,vector<int> vec;
(3)尾部插入数字:vec.push_back(a);
(4)使用下标访问元素,cout<<vec[0]<<endl;记住下标是从0开始的。
(5)使用迭代器访问元素.
vector<int>::iterator it; for(it=vec.begin();it!=vec.end();it++) cout<<*it<<endl;
(6)插入元素: vec.insert(vec.begin()+i,a);在第i+1个元素前面插入a;
(7)删除元素: vec.erase(vec.begin()+2);删除第3个元素
vec.erase(vec.begin()+i,vec.end()+j);删除区间[i,j-1];区间从0开始
(8)向量大小:vec.size();
(9)清空:vec.clear();
2
vector的元素不仅仅可以使int,double,string,还可以是结构体,但是要注意:结构体要定义为全局的,否则会出错。下面是一段简短的程序代码:
#include<stdio.h> #include<algorithm> #include<vector> #include<iostream> using namespace std; typedef struct rect { int id; int length; int width;
//对于向量元素是结构体的,可在结构体内部定义比较函数,下面按照id,length,width升序排序。
bool operator< (const rect &a) const
{
if(id!=a.id)
return id<a.id;
else
{
if(length!=a.length)
return length<a.length;
else
return width<a.width;
}
} }Rect; int main() { vector<Rect> vec; Rect rect; rect.id=1; rect.length=2; rect.width=3; vec.push_back(rect); vector<Rect>::iterator it=vec.begin(); cout<<(*it).id<<' '<<(*it).length<<' '<<(*it).width<<endl; return 0; }
3 算法
(1) 使用reverse将元素翻转:需要头文件#include<algorithm>
reverse(vec.begin(),vec.end());将元素翻转(在vector中,如果一个函数中需要两个迭代器,
一般后一个都不包含.)
(2)使用sort排序:需要头文件#include<algorithm>,
sort(vec.begin(),vec.end());(默认是按升序排列,即从小到大).
可以通过重写排序比较函数按照降序比较,如下:
定义排序比较函数:
bool Comp(const int &a,const int &b)
{
return a>b;
}
调用时:sort(vec.begin(),vec.end(),Comp),这样就降序排序。