目录
三种方法讲解阿里巴巴面试题
在学习这个题目之前推荐小伙伴们先去看一下我的STL专栏,学习一下vector基本使用以及原理
面试题:在C++中,往vector中插入10万个数字,怎么做能保证性能较高?
我看到这个题目脑子里出现的第一个想法:首先就是想提前配置好空间,因为vector是动态分配空间存储数据,提前配置好空间就可以不用中途重新分配 ,接下来让我们一起看看有哪些方法可以提高性能吧,我们一起冲鸭!
方法一:在插入数据之前,提前分配内存,把空间开好
写代码测试一下,我用的是Visual Studio编写代码的;
先计算没有优化前花费的时间代码如下:
#include <iostream> //C++标准头文件
#include <vector>
#include <chrono>
using namespace std;
//这里就正常插入数据不做优化
int main()
{
//记录程序开始运行时的时间
auto begin_time = chrono::high_resolution_clock::now();
vector<int> v;
for (int i = 0; i < 100000; ++i)
{
//为了验证方便,我们把i当做数据直接插入
v.push_back(i);
}
//记录程序运行结束时的时间
auto finsh_time = chrono::high_resolution_clock::now();
//计算并输出花费的时间
auto timetaken = chrono::duration_cast<chrono::microseconds>(finsh_time - begin_time);
cout << "花费的时间: " << timetaken.count() << endl;
}
输出 花费时间: 46336
接下来是利用预先分配内存做优化,代码如下:
//这里利用提前分配内存进行优化
int main()
{
//记录程序开始运行时的时间
auto begin_time = chrono::high_resolution_clock::now();
vector<int> v;
//提前开空间
v.reserve(100000);
for (int i = 0; i < 100000; ++i)
{
//为了验证方便,我们把i当做数据直接插入
v.push_back(i);
}
//记录程序运行结束时的时间
auto finsh_time = chrono::high_resolution_clock::now();
//计算并输出花费的时间
auto timetaken = chrono::duration_cast<chrono::microseconds>(finsh_time - begin_time);
cout << "花费的时间: " << timetaken.count() << endl;
}
输出 花费的时间40563
从46336 -------------------->40563
可以看出来有效率的提升但是不明显!那么想一下还有哪里可以优化的?或者说哪些操作占用我们这么长的时间?不要急,我们继续向下看.
方法二:使用构造函数初始化
在想一下哪些操作占用我们这么久的时间呢?小伙伴们已经猜到了,没错就是进行了10万次的push_back()尾部插入操作耗费我们的时间?那么怎么解决?是的哇,利用我们vector的构造函数直接开好空间并且赋予初始值.
接下来看代码:
#include <iostream> //C++标准头文件
#include <vector>
#include <chrono>
using namespace std;
int main()
{
//记录程序开始运行时的时间
auto begin_time = chrono::high_resolution_clock::now();
vector<int> v(100000);
for (int i = 0; i < 100000; ++i)
{
v[i] = i;//一定注意这里的细节,直接用下标进行赋值
}
//记录程序运行结束时的时间
auto finsh_time = chrono::high_resolution_clock::now();
//计算并输出花费的时间
auto timetaken = chrono::duration_cast<chrono::microseconds>(finsh_time - begin_time);
cout << "花费的时间: " << timetaken.count() << endl;
return 0;
}
输出 花费的时间: 2624
我们的花费时间从 从46336 -------------------->40563-------------------->2624
哇塞这下震惊了,效率直接提升了一个数量级,从5位数直接变成4位数;
那么不废话,得到原因:使用下标赋值本质是一个直接的内存访问操作,直接对地址进行操作,通常是一个O(1)常数的时间操作.
方法三:使用emplace_back()
(这里讲的知识移动构造不要着急后边会讲解):emplace_back() 直接在向量尾部构造对象,避免了对象的拷贝或移动。这对于内置类型(如 int)并没有显著优势,但对于自定义类型或复杂类型可能会提高性能。
直接看代码:
#include <iostream> //C++标准头文件
#include <vector>
#include <chrono>
using namespace std;
int main()
{
//记录程序开始运行时的时间
auto begin_time = chrono::high_resolution_clock::now();
std::vector<int> vec;
vec.reserve(100000);
//填充向量
for (int i = 0; i < 100000; ++i)
{
vec.emplace_back(i);
}
//记录程序运行结束时的时间
auto finsh_time = chrono::high_resolution_clock::now();
//计算并输出花费的时间
auto timetaken = chrono::duration_cast<chrono::microseconds>(finsh_time - begin_time);
cout << "花费的时间: " << timetaken.count() << endl;
return 0;
}
输出 花费的时间: 38592
对比使用push_back()有点提升,但是不多,针对int这样的内置类型没有体现出来优势,但是针对自定义类型或者复杂类型可能会提高性能.
三种方法对比下来,使用方案二效率最高
总结:
针对这道题目来说,采用先初始化,然后使用下标赋值是性能最高的方法.
鸡汤
一遍不会没关系吖,多看几遍,我也是学了好多遍呢,小伙伴们肯定学的又快又好!!!最后希望写的内容对小伙伴们有所帮助,我写的如果有哪里不对的地方请指出来哦!让我们一起进步吖,任何疑问包括心情不好都可以找我聊聊,我很乐意当你的倾听者吖