索引与迭代器 - 哪个更有效?
index vs iterator - which would be more efficient?
我想知道如果我想遍历向量,以下哪种方法更有效。第一个选项:
int i;
for(i = 0; i<vector.size(); i++)
{
cout << vector[i];
}
或
第二种选择:
vector<type>::iterator it;
for(it = vector.begin(); it != vector.end(); it++)
{
cout << *it;
}
通往地狱的道路是用善意铺成的;或者在我们的例子中过早优化。编译器完成的优化应使每个循环等效。 让编译器为您工作,并在这种情况下专注于可读性和可维护性。正如其他人指出的那样,std::cout
是示例中的瓶颈,而不是循环本身。
如果您使用的是 C++11 或更高版本,则基于范围的 for 循环非常适合易于使用和可读性。
for (const auto & element : myVector)
{
cout << element;
}
否则,如果我需要知道元素的位置,我发现使用vector::size()
和索引方法更容易。如果我不关心这一点,那么我几乎总是使用vector<type>::iterator
.在我看来,这两种方法的可读性都是等效的,迭代器是所有各种 STL 容器的更标准的方法。
验证效率的一种方法是对代码进行计时,并在每个过程中运行压力测试。若要对代码进行计时,请使用<chorno>
头文件 (C++11)。
首先,创建一个向量,然后添加大量条目:
#include <vector>
// Create a stressed vector
std::vector<int> myVector;
for (int i = 0; i < 10000; i++)
myVector.push_back(i);
为了代码简单起见,我将每个方法添加到一个函数中:
方法 1
#include <vector>
#include <iostream>
void methodOne(std::vector<int> vector)
{
for (int i = 0; i < int(vector.size()); i++)
std::cout << vector[i] << std::endl; // don't forget to add a separation
}
方法 2
#include <vector>
#include <iostream>
void methodTwo(std::vector<int> vector)
{
for (auto it = vector.begin(); it != vector.end(); it++)
std::cout << *it << std::endl; // don't forget to add a separation
}
我还喜欢使用第三种方法,每种方法都使用:
方法 3
#include <vector>
#include <iostream>
void methodThree(std::vector<int> vector)
{
for (auto element : vector)
std::cout << element << std::endl;
}
现在,包含<chrono>
标头,并将此例程运行到您的main()
中,并创建Timer
类,如 Learn Cpp 中所述:
定时器类
#include <chorno>
class Timer
{
private:
// Type aliases to make accessing nested type easier
using clock_t = std::chrono::high_resolution_clock;
using second_t = std::chrono::duration<double, std::ratio<1> >;
std::chrono::time_point<clock_t> m_beg;
public:
Timer() : m_beg(clock_t::now())
{
}
void reset()
{
m_beg = clock_t::now();
}
double elapsed() const
{
return std::chrono::duration_cast<second_t>(clock_t::now() - m_beg).count();
}
};
现在,对于主函数,只需运行以下代码:
主要
#include <vector>
#include <iostream>
#include <chrono>
int main()
{
//Create a stressed vector
std::vector<int> myVector;
for (int i = 0; i < 10000; i++)
myVector.push_back(i);
Timer t;
t.reset();
t.reset();
methodOne(myVector);
auto t1 = t.elapsed();
t.reset();
methodTwo(myVector);
auto t2 = t.elapsed();
t.reset();
methodThree(myVector);
auto t3 = t.elapsed();
std::cout << "n";
std::cout << "Time for Method 1 = " << t1 << " secondsn";
std::cout << "Time for Method 2 = " << t2 << " secondsn";
std::cout << "Time for Method 3 = " << t3 << " secondsn";
return 0;
}
以下是不同应力向量的代码输出:
条目数 = 100:
Time for Method 1 = 0.146709 seconds
Time for Method 2 = 0.176648 seconds
Time for Method 3 = 0.16161 seconds
条目数 = 1000
Time for Method 1 = 1.67696 seconds
Time for Method 2 = 1.63569 seconds
Time for Method 3 = 1.64162 seconds
条目数 = 3000
Time for Method 1 = 5.07384 seconds
Time for Method 2 = 5.01691 seconds
Time for Method 3 = 5.00742 seconds
条目数 = 7000
Time for Method 1 = 11.8177 seconds
Time for Method 2 = 5.91258 seconds
Time for Method 3 = 3.52884 seconds
条目数 = 15000
Time for Method 1 = 18.7798 seconds
Time for Method 2 = 8.2039 seconds
Time for Method 3 = 8.25364 seconds
所有这些测试都是使用发布版本 x86 执行的。
在查看这些数字后,我们可以得出结论,对于少数条目,这两种方法都很好用。但是随着条目数量的增加,方法 1 似乎需要更多时间来完成相同的任务,尽管我们正在喷出整数。也许其他变量类型可能会导致不同的结果。
话虽如此,我看到方法 2 和提出的方法 3 在处理巨大的循环和向量时更有效。
- 钳制迭代器是否有效
- 为什么以这种方式使用迭代器有效?
- 如何将迭代器(包括结束和开始之前的迭代器)测试到列表或forward_list保持有效
- 索引与迭代器 - 哪个更有效?
- 有效的迭代器范围从堆栈上的char
- 如何普遍有效地填充缓冲液?(传递插入迭代器?器皿?等)
- 字符串::替换在有效的迭代器上抛出 std::out_of_range
- 如何检查迭代器指定的范围是否有效
- 检查迭代器是否对QT容器有效
- 无法使用迭代器遍历字符串:但是我的带有索引的版本确实有效
- Const与非Const迭代器的比较是否有效
- 如何在C++中返回有效的迭代器
- 获得映射迭代器索引的最有效方法?c++
- 使用迭代器访问映射的特定键的最有效方法
- 检查简化迭代器是否指向有效元素
- std::map::erase(it++)是否维护一个指向映射中下一个元素的有效迭代器
- 在擦除()之后保留一个有效的向量::迭代器
- 如何简化检查搜索算法返回的迭代器是否有效
- 有效地计数两个std::multimap迭代器之间的条目数
- 对迭代器解引用时是否有效?