如何使用迭代器在向量中导航?(C ++)


105

目标是访问字符串向量的“ nth”元素,而不是[]运算符或“ at”方法。据我了解,迭代器可用于在容器中导航,但我以前从未使用过迭代器,而我正在阅读的内容令人困惑。

如果有人能给我一些有关如何实现这一目标的信息,我将不胜感激。谢谢。


向量不是C ++的STL专有的吗?无论如何我都会对其进行编辑
凯文(Kevin)2010年

kevin:向量是一个通用术语,任何语言都可以使用,尤其是与数学相关的语言,例如Mathematica或Matlab。
加布

@michael,是的,我在gabe评论后编辑了它。
凯文2010年

Answers:


112

您需要使用类的beginend方法vector,它们分别返回引用第一个和最后一个元素的迭代器。

using namespace std;  

vector<string> myvector;  // a vector of stings.


// push some strings in the vector.
myvector.push_back("a");
myvector.push_back("b");
myvector.push_back("c");
myvector.push_back("d");


vector<string>::iterator it;  // declare an iterator to a vector of strings
int n = 3;  // nth element to be found.
int i = 0;  // counter.

// now start at from the beginning
// and keep iterating over the element till you find
// nth element...or reach the end of vector.
for(it = myvector.begin(); it != myvector.end(); it++,i++ )    {
    // found nth element..print and break.
    if(i == n) {
        cout<< *it << endl;  // prints d.
        break;
    }
}

// other easier ways of doing the same.
// using operator[]
cout<<myvector[n]<<endl;  // prints d.

// using the at method
cout << myvector.at(n) << endl;  // prints d.

5
这错过了std::vector具有随机访问迭代器的事实。
2010年

24
不管您是否知道迭代器类型是否为随机访问,将迭代器向前移动n个空间的“最佳”方法不是编写自己的循环,而是调用std::advance(it, n)。它的定义完全可以满足您的要求,it + n如果将迭代器标记为随机访问,它将自动使用它;如果需要,则可以执行循环。
史蒂夫·杰索普

61

通常,迭代器用于以线性方式访问容器的元素。但是,通过“随机访问迭代器”,可以用与相同的方式访问任何元素operator[]

访问vector中的任意元素 vec,可以使用以下命令:

vec.begin()                  // 1st
vec.begin()+1                // 2nd
// ...
vec.begin()+(i-1)            // ith
// ...
vec.begin()+(vec.size()-1)   // last

以下是典型访问模式(C ++的早期版本)的示例:

int sum = 0;
using Iter = std::vector<int>::const_iterator;
for (Iter it = vec.begin(); it!=vec.end(); ++it) {
    sum += *it;
}

使用迭代器的优点是可以将相同的模式应用于其他容器

sum = 0;
for (Iter it = lst.begin(); it!=lst.end(); ++it) {
    sum += *it;
}

因此,创建无论容器类型如何都相同的模板代码确实很容易。迭代器的另一个优点是它不假定数据驻留在内存中。例如,可以创建一个正向迭代器,该正向迭代器可以从输入流中读取数据,或者可以简单地动态生成数据(例如,范围或随机数生成器)。

使用std::for_each和lambdas的另一种选择:

sum = 0;
std::for_each(vec.begin(), vec.end(), [&sum](int i) { sum += i; });

从C ++ 11开始,您auto可以避免指定一个很长,很复杂的迭代器类型名称,如之前所见(或更复杂):

sum = 0;
for (auto it = vec.begin(); it!=vec.end(); ++it) {
    sum += *it;
}

此外,还有一个更简单的for-each变体:

sum = 0;
for (auto value : vec) {
    sum += value;
}

最后,std::accumulate无论添加整数还是浮点数,都必须要小心。


53

在C ++-11中,您可以执行以下操作:

std::vector<int> v = {0, 1, 2, 3, 4, 5};
for (auto i : v)
{
   // access by value, the type of i is int
   std::cout << i << ' ';
}
std::cout << '\n';

看到这里的变化:https : //en.cppreference.com/w/cpp/language/range-for


4
为什么有零赞?!<3
jperl

3
@jperl发表晚8年。接下来的8年将获得足够的支持:)
lashgar '18

@jperl,那么答案就离题了。尽管此循环功能不错,但它不能帮助您知道何时处于第n个元素,这是OP的问题。另外,任何需要O(n)时间复杂度的答案(例如此答案)都是非常糟糕的。访问向量的第n个元素应始终为O(1)。
Elliott

@lashgar我尝试使用数组,但是失败了。它适用于数组吗?
时代s'q

@ eras'q,7.5.0在Ubuntu 18.04上使用gcc尝试过,并且以相同的方式用于数组。
lashgar

17

Vector的迭代器是随机访问迭代器,这意味着它们的外观看起来像普通指针。

您可以通过在容器begin()方法返回的迭代器中添加n来访问第n个元素,也可以使用operator []

std::vector<int> vec(10);
std::vector<int>::iterator it = vec.begin();

int sixth = *(it + 5);
int third = *(2 + it);
int second = it[1];

另外,您可以使用与所有迭代器一起使用的高级功能。(您必须考虑是否真的要使用非随机访问迭代器执行“随机访问”,因为这样做可能会很昂贵。)

std::vector<int> vec(10);
std::vector<int>::iterator it = vec.begin();

std::advance(it, 5);
int sixth = *it;

1
您也可以将其advance用于随机访问迭代器,也可以用于未知类别的迭代器,因为在这种情况下,它可以保证恒定的时间运行。这就是为什么应正确标记用户定义的迭代器的原因。
史蒂夫·杰索普

的确如此,但是advance如果您知道要处理随机访问迭代器,则使用它确实很烦人(由于使用了out参数)。仅在通用代码中推荐使用,并且如果不常用的话(如果该算法不能很好地支持非随机访问迭代器,那么就可以了-例如,std::sort 可以排序,std::list但不能,因为它效率极低) )。
UncleBens

当然,经典的例子是您的算法实际上只需要一个InputIterator,但是由于某种原因它有时会跳过,所以如果迭代器确实具有随机访问权限,您希望它更有效率。仅通过使用将您的算法限制为随机访问是不值得的operator+。但是问题显然是关于向量的,因此答案的第一部分没有任何问题。我只是以为第二部分可能暗示对以前从未见过的人“即使您愿意,也不能对随机访问迭代器使用高级” advance
史蒂夫·杰索普

好的,改写该位,并给出带有矢量的示例。
UncleBens

第二行,Vector应该是小写
雷扬

0

这是一个在循环内使用a 的ith索引的示例,该循环不需要递增两个迭代器。std::vectorstd::iterator

std::vector<std::string> strs = {"sigma" "alpha", "beta", "rho", "nova"};
int nth = 2;
std::vector<std::string>::iterator it;
for(it = strs.begin(); it != strs.end(); it++) {
    int ith = it - strs.begin();
    if(ith == nth) {
        printf("Iterator within  a for-loop: strs[%d] = %s\n", ith, (*it).c_str());
    }
}

没有for循环

it = strs.begin() + nth;
printf("Iterator without a for-loop: strs[%d] = %s\n", nth, (*it).c_str());

和使用at方法:

printf("Using at position: strs[%d] = %s\n", nth, strs.at(nth).c_str());
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.