반복기를 사용하여 벡터를 탐색하는 방법은 무엇입니까? (C ++)


105

목표는 [] 연산자 나 "at"메서드 대신 문자열 벡터의 "n 번째"요소에 액세스하는 것입니다. 내가 이해하는 바에 따르면 반복기를 컨테이너를 탐색하는 데 사용할 수 있지만 이전에는 반복기를 사용한 적이 없으며 읽고있는 내용이 혼란 스럽습니다.

누구든지 이것을 달성하는 방법에 대한 정보를 줄 수 있다면 감사하겠습니다. 감사합니다.


벡터는 C ++의 STL에만 국한되지 않습니까? 나는 관계없이 편집합니다
— 케빈

kevin : 벡터는 모든 언어, 특히 Mathematica 또는 Matlab과 같은 수학 관련 언어에서 사용할 수있는 일반적인 용어입니다.
— Gabe

@michael, 그래 haha ​​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있으며 반복자가 임의 액세스로 태그가 지정되면 자동으로 사용하고 필요한 경우 루프를 수행합니다.
— Steve Jessop

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;
}

이러한 이유로 컨테이너 유형에 관계없이 동일하게 작동하는 템플릿 코드를 만드는 것은 정말 쉽습니다. . 반복자의 또 다른 장점은 데이터가 메모리에 상주한다고 가정하지 않는다는 것입니다. 예를 들어, 입력 스트림에서 데이터를 읽을 수있는 순방향 반복기를 만들거나 단순히 즉석에서 데이터를 생성하는 (예 : 범위 또는 난수 생성기) 만들 수 있습니다.

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
왜 좋아요가 0인가요?! <3
— jperl

3
@jperl 8 년 늦게 게시 됨. 충분한
— 찬성 투표

@jperl, 대답은 주제에서 벗어났습니다. 이 루프 기능은 좋지만 OP의 질문 인 n 번째 요소에있을 때 알 수는 없습니다. 또한, 이와 같이 O (n) 시간 복잡성이 필요한 모든 답변은 매우 나쁩니다. 벡터의 n 번째 요소에 액세스하는 것은 항상 O (1)이어야합니다.
— Elliott

@lashgar 배열로 시도했지만 실패했습니다. 어레이에서 작동합니까?
— era s'q

@ eras'q, 7.5.0Ubuntu 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랜덤 액세스 반복자 또는 알 수없는 범주의 반복자에도 사용할 수 있습니다 .이 경우 일정한 시간에 작동하도록 보장되기 때문입니다. 이것이 사용자 정의 반복기가 올바르게 태그되어야하는 이유입니다.
— Steve Jessop

사실,하지만 advance랜덤 액세스 반복자를 다루는 것을 안다면 (out 매개 변수 사용으로 인해) 사용하기가 정말 짜증납니다. 단지 일반적인 코드에서 추천 할 것, 그리고 (많이 사용하지 않을 경우 알고리즘이 잘 아닌 임의 접근 반복자를 지원하지 않는 경우, 그래서 수 - 예를 들어, std::sort 수 를 정렬 std::list하지만 그것이 엄청나게 비효율적하지 않기 때문에 ).
— UncleBens 2010 년

물론 고전적인 예는 알고리즘에 실제로 InputIterator 만 필요한 경우이지만 어떤 이유로 든 간혹 건너 뛰기 때문에 반복기에 임의 액세스 권한이있는 경우 더 효율적 이길 원합니다. 을 사용하여 알고리즘을 임의 액세스로 제한하는 것은 가치가 없습니다 operator+. 그러나 질문은 명시 적으로 벡터에 관한 것이기 때문에 답변의 첫 번째 부분에는 잘못된 것이 없습니다. 두 번째 부분은 "원한다고해도 랜덤 액세스 반복기와 함께 advance를 사용할 수 없다"는 것을 advance전에 본 적이없는 사람에게 암시 할 수 있다고 생각했습니다 .
— Steve Jessop

좋아, 그 비트를 바꾸고 벡터로 예제를 주었다.
— UncleBens 2010 년

둘째 줄은 Vector소문자되어야
— 레이 양

0

다음은 두 반복자를 증가시킬 필요가없는 루프 내에서 사용하여 의 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.