索引与迭代器 - 哪个更有效?

index vs iterator - which would be more efficient?

本文关键字:有效 迭代器 索引      更新时间:2023-10-16

我想知道如果我想遍历向量,以下哪种方法更有效。第一个选项:

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 在处理巨大的循环和向量时更有效。