イテレータを使用してベクトルをナビゲートする方法は?(C ++)


105

目的は、[]演算子や「at」メソッドではなく、文字列のベクトルの「n番目」の要素にアクセスすることです。私が理解していることから、コンテナをナビゲートするためにイテレータを使用できますが、これまでイテレータを使用したことがなく、読んでいるものは混乱しています。

これを達成する方法について誰かが私にいくつかの情報を提供できたら、私はそれを感謝します。ありがとうございました。


C ++のSTL専用のベクターではありませんか?関係なく編集します
ケビン

kevin:ベクトルは、あらゆる言語、特にMathematicaやMatlabなどの数学関連の言語で使用できる一般的な用語です。
Gabe

@michael、ええ笑gabeさんのコメントの後で編集しました。
ケビン

回答:


112

クラスのbeginおよびendメソッドを使用する必要があり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ランダムアクセス反復子を持つという事実を見逃しています。
sbi

24
イテレータのタイプがランダムアクセスであるかどうかに関係なく、イテレータをnスペース前に移動する「最善の」方法は、独自のループを作成するのではなく、を呼び出すことstd::advance(it, n)です。それはあなたが望むことを正確に実行するように定義されてit + nおり、イテレータがランダムアクセスとしてタグ付けされている場合は自動的に使用し、そうでなければループを実行します。
スティーブジェソップ

61

通常、イテレータはコンテナの要素に線形的にアクセスするために使用されます。ただし、「ランダムアクセス反復子」を使用すると、と同じ方法で任意の要素にアクセスできますoperator[]

ベクトルでのアクセス任意の要素 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;
}

このため、コンテナタイプに関係なく同じように機能するテンプレートコードを作成するのは非常に簡単です。イテレータのもう1つの利点は、データがメモリに常駐していることを前提としないことです。たとえば、入力ストリームからデータを読み取ることができる、またはその場でデータを生成するだけのフォワードイテレータ(たとえば、範囲または乱数ジェネレータ)を作成できます。

std::for_eachとラムダを使用する別のオプション:

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 2018

3
@jperl 8年遅れて投稿されました。十分な賛成票を獲得するには、今後8年かかります:)
ラッシュガー

@jperl、まあ答えはトピック外です。このループ機能は便利ですが、OPの質問であるn番目の要素に到達したことを知るのに役立ちません。また、このようなO(n)時間の複雑さを必要とする回答はすべて非常に悪いものです。ベクトルのn番目の要素へのアクセスは常にO(1)である必要があります。
エリオット

@lashgar配列でこれを試しましたが失敗しました。アレイで機能しますか?
era s'q

@ eras'q、7.5.0Ubuntu 18.04 でgcc を試してみて、アレイと同じように機能します。
ラッシュガー

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+。しかし、問題は明示的にベクトルに関するものだったので、答えの最初の部分に問題はありません。2番目の部分は、「ランダムアクセスイテレータでAdvanceを使用することはできません」と、これまでに見たことのない人に示唆しているのではないかと思いましたadvance
スティーブジェソップ

OK、そのビットを言い換えて、例をベクトルで示した。
UncleBens

2行目Vectorは小文字にする必要があります
Lei Yang

0

2つの反復子をインクリメントする必要のないループ内でを使用しての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());
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.