C++ STL vector遍历方式及其效率分析
++i和i++区别
++i使用的是i执行完+1后的值可以直接使用,而i++是先使用i然后在对i进行+1这样就需要一个临时变量去进行转储,虽然只是一个简单的操作但是在循环中这一操作就会被循环次数而放大。如果i是一个简单的int型变量在很多编译器里面会优化这种写法,但是如果i是一个迭代器那么循环的性能就会收到影响,具体大小受到循环次数的约束。笔者亲测在QT中部分源码以及输出如下:
std::vector<int> iv;
int i;
for(i=0;i<10000000;++i)
{
iv.push_back(i);
}
QDateTime dateTime = QDateTime::currentDateTime();
qDebug()<<dateTime.toString("yyyy-MM-dd hh:mm:ss.zzz");
auto iter=iv.begin();
for(iter;iter!=iv.end();++iter)
{
int a = *iter;
}
dateTime = QDateTime::currentDateTime();
qDebug()<<dateTime.toString("yyyy-MM-dd hh:mm:ss.zzz");
iter=iv.begin();
for(iter;iter!=iv.end();iter++)
{
int a = *iter;
}
dateTime = QDateTime::currentDateTime();
qDebug()<<dateTime.toString("yyyy-MM-dd hh:mm:ss.zzz");
输出:
"2021-10-19 11:29:11.488"
"2021-10-19 11:29:11.593"
"2021-10-19 11:29:11.738"
++iter循环1000万次耗时105毫秒
iter++循环1000万次耗时145毫秒
由上例可以看出++iter和iter++的区别
下标遍历
直接上代码:
std::vector<int> iv;
int i;
for(i=0;i<10000000;++i)
{
iv.push_back(i);
}
int size = iv.size();
QDateTime dateTime = QDateTime::currentDateTime();
qDebug()<<dateTime.toString("yyyy-MM-dd hh:mm:ss.zzz");
for(i=0;i<size;++i)
{
int a = iv[i];
}
dateTime = QDateTime::currentDateTime();
qDebug()<<dateTime.toString("yyyy-MM-dd hh:mm:ss.zzz");
输出为:
"2021-10-19 11:56:25.258"
"2021-10-19 11:56:25.280"
循环1000万次耗时22毫秒
使用at方法取值:
std::vector<int> iv;
int i;
for(i=0;i<10000000;++i)
{
iv.push_back(i);
}
int size = iv.size();
QDateTime dateTime = QDateTime::currentDateTime();
qDebug()<<dateTime.toString("yyyy-MM-dd hh:mm:ss.zzz");
for(i=0;i<size;++i)
{
int a = iv.at(i);
}
dateTime = QDateTime::currentDateTime();
qDebug()<<dateTime.toString("yyyy-MM-dd hh:mm:ss.zzz");
输出为:
"2021-10-19 13:28:21.609"
"2021-10-19 13:28:21.699"
循环1000万次耗时90毫秒
迭代器遍历
直接上代码:
std::vector<int> iv;
for(i=0;i<10000000;++i)
{
iv.push_back(i);
}
QDateTime dateTime = QDateTime::currentDateTime();
qDebug()<<dateTime.toString("yyyy-MM-dd hh:mm:ss.zzz");
auto iter=iv.begin();
for(iter;iter!=iv.end();++iter)
{
int a = *iter;
}
dateTime = QDateTime::currentDateTime();
qDebug()<<dateTime.toString("yyyy-MM-dd hh:mm:ss.zzz");
输出:
"2021-10-19 11:56:25.280"
"2021-10-19 11:56:25.382"
耗时102毫秒
for_each遍历
直接上代码:
template<typename T>
void fun(const T a)
{
int b=a;
}
int main(int argc, char *argv[])
{
std::vector<int> iv;
int i;
for(i=0;i<10000000;++i)
{
iv.push_back(i);
}
QDateTime dateTime = QDateTime::currentDateTime();
qDebug()<<dateTime.toString("yyyy-MM-dd hh:mm:ss.zzz");
std::for_each(iv.begin(),iv.end(),fun<int>);
dateTime = QDateTime::currentDateTime();
qDebug()<<dateTime.toString("yyyy-MM-dd hh:mm:ss.zzz");
}
输出为:
"2021-10-19 13:25:01.119"
"2021-10-19 13:25:01.199"
耗时90毫秒
总结
由上面例子可以看出,vector遍历最快的是下标遍历,但是下表遍历可能会出现超出范围的风险现,但是如果使用at方法获取vector中的值会导致效率降低。
下面科普下计算时间和电脑CPU之间的关系。现在普遍CPU的主频是1GHz到4GHz,意思是CPU一秒处理基础运算的次数,由此可以换算出一毫秒CPU处理基础运算的次数这里为了直观的数据体验使用1000为进制单位代替1024,一毫秒CPU可以运算100万到400万次 ,1000万次循环下标遍历和迭代器遍历可以差80毫秒也就是可以减少CPU基础运算800万到3200万次(假设CPU满负荷运算节省的80毫秒可以用来运算其他功能),可以推算出大约每10次循环可以节省8到32次基础运算。当然以上推论都是估算如有问题望指正。