CS/자료구조 & 알고리즘

이터레이터 Iterator (반복자)

ShovelingLife 2022. 6. 16. 18:00
  • 컨테이너에 저장되있는 원소들을 공통적인 방법으로 하나씩 접근할 수 있게 해줌. 모든 컨테이너들이 다 같은 방법으로 반복자 사용 가능.
  • 각 타입에 ::iterator 또는 ::const_iterator 를 뒤에 붙여주면 사용이 가능하다.
    • vector 컨테이너의 반복자 itr vector<int>::iterator itr;
    • vector 컨테이너의 const한 반복자 citr vector<int>::const_iterator citr;
  • 포인터와 비슷하게 사용한다.
    • 간접 참조 가능) itr = v.begin() + 2 에서 *itr 간접 참조를 하면 세번째 원소 값이 리턴된다.
  • iterator 와 const_iterator 의 차이
    • const_iterator 는 반복자가 가리키는 원소의 값을 변경하지 못한다. 반복자 값이 변경되지 못하는게 아니고 반복자가 가리키는 원소의 값이 변경될 수 없는 것!
    • 일반 반복자는 포인터와 비슷하고 const 반복자는 const 포인터와 비슷하다. (간접참조로 값을 변경하지 못하는)
  • 초기화 하는 방법
    • itr = container.begin() 컨테이너이름.begin() 하면 첫번째 원소의 iterator를 리턴

반복자도 종류가 있다. 산술 연산이 가능한건 “임의 접근 반복자”를 가지는 vector, deque 밖에 없다.

STL 의 모든 컨테이너 혹은 함수들은 아래와 같은 종류의 반복자들을 지원하는데, 아래 반복자들 중 어느 것들까지 지원을 하느냐에 따라 사용할 수 있는 연산, 함수들이 달라진다.

컨테이너마다 지원하는 반복자의 종류가 다르다.

입력 반복자(Input)

  • Read 및 접근 만 가능.
  • Write 불가능
  • 증감은 ++ 연산만 가능.
  • 비교는 ==, != 연산만 가능.
cout << itr->size() << endl; // 접근 ⭕
뫄뫄 = *itr;  // 읽기 가능 ⭕ (간접 참조처럼 * 연산자)
itr++; // ++ 연산 가능 ⭕
if (itr1 == itr2); // ⭕
*itr = 뫄뫄;  // 쓰기 불가능 ❌ (간접 참조 수정 불가)

출력 반복자(Output)

  • Write 만 가능.
  • Read 및 접근 불가능
  • ++ 연산만 가능. (itr++)
  • 비교 연산자 불가능
cout << itr->size() << endl; // 접근 불가능 ❌
뫄뫄 = *itr;  // 읽기 불가능 ❌
itr++; // ++ 연산 가능 ⭕
if (itr1 == itr2); // 비교 연산 불가능 ❌
*itr = 뫄뫄;  // 쓰기 가능 ⭕

순방향 반복자(Forward)

  • 읽기 쓰기 접근 다된다.
  • 산술 연산 👉 ++만 가능
  • 비교 연산 👉 ==, !=만 가능

양방향 반복자(Bidirectional)

  • 읽기 쓰기 접근 다된다.
  • 산술 연산 👉 ++, -- 가능
  • 비교 연산 👉 ==, !=만 가능

list, set, map 은 이 반복자를 지원한다. (그래서 set 의 반복자끼리 뺄셈을 하려 했을 때 불가능했던 것이다.)

이 양방향 반복자를 지원하지 않는 컨테이너는 알고리즘 헤더의 reverse() 함수를 사용할 수 없다. reverse 함수는 이 양방향 반복자를 사용하기 때문이다. 이처럼 함수, 연산에 따라 사용할 수 있는 반복자가 정해져있다는 것을 꼭 알아두자!

임의접근 반복자(Random Access))

  • 읽기 쓰기 접근 다된다.
  • 산술 연산 👉 ++, --, ✨+, -, +=, -= 가능✨
  • 비교 연산 👉 ==, !=, ✨>, <, >=, <= 가능✨
  • 첨자 연산자 사용 가능 👉 []
    • itr[n]은 곧 *(itr + n)과도 같다.
      vector<int>::iterator itr;
      itr[4];  // itr 에서 4 칸 더 간 곳의 반복자! 
      

vector, deque 는 이 반복자를 지원한다. 그래서 반복자끼리 사칙연산을 해야한다면 vector를 사용해야 한다.

#include <iostream>
#include <vector>
#include <map>
 
using namespace std;
 
int main()
{
    int count = 0, n; cin >> n;
    int* arr= new int[n];
 
    cout << "\n포인터 이터레이터 시작" << endl;
 
    for (auto iter = arr; iter < arr + n; iter++)
    {
        *iter = 10 + (count++);
        cout << *iter << endl;
    }
    count = 0;
    cout << "\n벡터 이터레이터 시작" << endl;
 
    // 벡터 생성 후 대입
    vector<map<int, int>> v(n);
 
    for (int i = 0; i < n; i++)
        v[i].insert({ i, arr[i] });
 
    for (auto iter = v.begin(); iter != v.end(); iter++)
        cout << iter->at(count++) << endl;
 
    delete[] arr;
}

출처 : https://ansohxxn.github.io/stl/chapter16-2/