STL 반복자

2025. 3. 28. 08:54Programming Languages/C++

8.3 STL 반복자

반복자(Iterator)는 컨테이너의 요소에 접근하고 순회하는 통일된 방법을 제공합니다.

8.3.1 반복자 개념과 카테고리

STL은 다음과 같은 반복자 카테고리를 정의합니다:

  1. 입력 반복자(Input Iterator): 한 번에 한 방향으로만 이동 가능, 읽기 전용
  2. 출력 반복자(Output Iterator): 한 번에 한 방향으로만 이동 가능, 쓰기 전용
  3. 순방향 반복자(Forward Iterator): 한 방향으로 여러 번 이동 가능
  4. 양방향 반복자(Bidirectional Iterator): 양방향으로 이동 가능
  5. 임의 접근 반복자(Random Access Iterator): 임의의 위치로 바로 이동 가능
#include <iostream>
#include <vector>
#include <list>
#include <map>
#include <iterator>  // 반복자 도구
#include <algorithm>  // for_each

int main() {
    // 컨테이너 생성
    std::vector<int> vec = {1, 2, 3, 4, 5};  // 임의 접근 반복자 제공
    std::list<int> lst = {10, 20, 30, 40, 50};  // 양방향 반복자 제공
    std::map<std::string, int> mp = {{"one", 1}, {"two", 2}, {"three", 3}};  // 양방향 반복자 제공
    
    // 기본 반복자 사용
    std::cout << "벡터 요소: ";
    for (std::vector<int>::iterator it = vec.begin(); it != vec.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;
    
    // auto를 사용한 간결한 방법 (C++11)
    std::cout << "리스트 요소: ";
    for (auto it = lst.begin(); it != lst.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;
    
    // 맵 반복자 (pair 반환)
    std::cout << "맵 요소:" << std::endl;
    for (auto it = mp.begin(); it != mp.end(); ++it) {
        std::cout << "  " << it->first << ": " << it->second << std::endl;
    }
    
    // 역방향 반복자
    std::cout << "벡터 요소 (역순): ";
    for (auto rit = vec.rbegin(); rit != vec.rend(); ++rit) {
        std::cout << *rit << " ";
    }
    std::cout << std::endl;
    
    // 상수 반복자 (읽기 전용)
    std::cout << "리스트 요소 (상수 반복자): ";
    for (std::list<int>::const_iterator it = lst.cbegin(); it != lst.cend(); ++it) {
        // *it = 100;  // 오류: 상수 반복자는 수정 불가
        std::cout << *it << " ";
    }
    std::cout << std::endl;
    
    // 반복자로 값 수정
    for (auto it = vec.begin(); it != vec.end(); ++it) {
        *it *= 2;  // 각 요소를 2배로
    }
    
    // 벡터의 임의 접근 반복자 기능
    auto it = vec.begin();
    std::cout << "세 번째 요소: " << it[2] << std::endl;  // 배열처럼 접근
    it += 2;  // 두 단계 전진
    std::cout << "현재 요소: " << *it << std::endl;
    it -= 1;  // 한 단계 후퇴
    std::cout << "현재 요소: " << *it << std::endl;
    
    // 반복자 간 거리
    auto first = vec.begin();
    auto last = vec.end();
    std::cout << "벡터 요소 수: " << std::distance(first, last) << std::endl;
    
    // for_each 알고리즘과 반복자
    std::cout << "맵 요소 (for_each 사용): " << std::endl;
    std::for_each(mp.begin(), mp.end(), [](const auto& pair) {
        std::cout << "  " << pair.first << ": " << pair.second << std::endl;
    });
    
    // 스트림 반복자 사용
    std::cout << "숫자 입력 (Ctrl+D로 종료): ";
    std::istream_iterator<int> input_iter(std::cin);
    std::istream_iterator<int> eos;  // 끝 반복자
    
    std::vector<int> input_numbers;
    std::copy(input_iter, eos, std::back_inserter(input_numbers));
    
    std::cout << "입력한 숫자: ";
    std::copy(input_numbers.begin(), input_numbers.end(), 
              std::ostream_iterator<int>(std::cout, " "));
    std::cout << std::endl;
    
    return 0;
}

8.3.2 특수 반복자

삽입 반복자(Insert Iterators)

#include <iostream>
#include <vector>
#include <list>
#include <set>
#include <iterator>
#include <algorithm>

int main() {
    std::vector<int> source = {1, 2, 3, 4, 5};
    
    // back_inserter: push_back을 사용하여 뒤에 삽입
    std::vector<int> dest1;
    std::copy(source.begin(), source.end(), std::back_inserter(dest1));
    
    std::cout << "back_inserter 결과: ";
    for (const auto& elem : dest1) {
        std::cout << elem << " ";
    }
    std::cout << std::endl;
    
    // front_inserter: push_front를 사용하여 앞에 삽입 (리스트와 같은 컨테이너에만 사용 가능)
    std::list<int> dest2;
    std::copy(source.begin(), source.end(), std::front_inserter(dest2));
    
    std::cout << "front_inserter 결과: ";
    for (const auto& elem : dest2) {
        std::cout << elem << " ";  // 역순으로 출력됨: 5 4 3 2 1
    }
    std::cout << std::endl;
    
    // inserter: 지정된 위치에 삽입
    std::vector<int> dest3 = {10, 20, 30};
    std::copy(source.begin(), source.end(), std::inserter(dest3, dest3.begin() + 1));
    
    std::cout << "inserter 결과: ";
    for (const auto& elem : dest3) {
        std::cout << elem << " ";  // 10 1 2 3 4 5 20 30
    }
    std::cout << std::endl;
    
    // set에 삽입
    std::set<int> dest4;
    std::copy(source.begin(), source.end(), std::inserter(dest4, dest4.end()));
    
    std::cout << "set inserter 결과: ";
    for (const auto& elem : dest4) {
        std::cout << elem << " ";
    }
    std::cout << std::endl;
    
    return 0;
}

스트림 반복자(Stream Iterators)

#include <iostream>
#include <fstream>
#include <iterator>
#include <vector>
#include <algorithm>
#include <string>

int main() {
    // 파일에서 정수 읽기
    std::ifstream in_file("numbers.txt");
    if (!in_file) {
        std::cerr << "Could not open numbers.txt" << std::endl;
        return 1;
    }
    
    std::istream_iterator<int> file_iter(in_file);
    std::istream_iterator<int> eof;
    
    std::vector<int> numbers(file_iter, eof);
    
    // 읽은 숫자 출력
    std::cout << "파일에서 읽은 숫자: ";
    std::copy(numbers.begin(), numbers.end(), 
              std::ostream_iterator<int>(std::cout, " "));
    std::cout << std::endl;
    
    // 표준 입력에서 문자열 읽기
    std::cout << "몇 개의 단어를 입력하세요 (Ctrl+D로 종료): ";
    std::istream_iterator<std::string> word_iter(std::cin);
    std::istream_iterator<std::string> word_eof;
    
    std::vector<std::string> words(word_iter, word_eof);
    
    // 읽은 단어 정렬 후 출력
    std::sort(words.begin(), words.end());
    
    std::cout << "정렬된 단어: ";
    std::copy(words.begin(), words.end(), 
              std::ostream_iterator<std::string>(std::cout, " "));
    std::cout << std::endl;
    
    // 파일에 숫자 쓰기
    std::ofstream out_file("sorted_numbers.txt");
    if (!out_file) {
        std::cerr << "Could not create sorted_numbers.txt" << std::endl;
        return 1;
    }
    
    std::sort(numbers.begin(), numbers.end());
    std::copy(numbers.begin(), numbers.end(), 
              std::ostream_iterator<int>(out_file, "\n"));
    
    std::cout << "정렬된 숫자를 sorted_numbers.txt에 저장했습니다." << std::endl;
    
    return 0;
}

역방향 반복자(Reverse Iterators)

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};
    
    // 정방향 반복자로 출력
    std::cout << "정방향: ";
    for (auto it = vec.begin(); it != vec.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;
    
    // 역방향 반복자로 출력
    std::cout << "역방향: ";
    for (auto rit = vec.rbegin(); rit != vec.rend(); ++rit) {
        std::cout << *rit << " ";
    }
    std::cout << std::endl;
    
    // 알고리즘에서 역방향 반복자 사용
    std::vector<int> dest(vec.size());
    std::copy(vec.rbegin(), vec.rend(), dest.begin());
    
    std::cout << "역순으로 복사: ";
    for (const auto& elem : dest) {
        std::cout << elem << " ";
    }
    std::cout << std::endl;
    
    // 반복자 변환
    auto it = vec.begin() + 2;  // 세 번째 요소 가리킴
    std::cout << "it가 가리키는 값: " << *it << std::endl;  // 3
    
    // 정방향 -> 역방향
    auto rit = std::vector<int>::reverse_iterator(it);
    std::cout << "rit가 가리키는 값: " << *rit << std::endl;  // 2 (주의: 이전 요소)
    
    // 역방향 -> 정방향
    auto it2 = rit.base();
    std::cout << "it2가 가리키는 값: " << *it2 << std::endl;  // 3
    
    return 0;
}

 

'Programming Languages > C++' 카테고리의 다른 글

함수 객체와 람다 표현식  (0) 2025.03.28
STL 알고리즘  (0) 2025.03.28
STL 컨테이너  (0) 2025.03.28
STL (Standard Template Library)  (0) 2025.03.28
챕터7. 실습 문제  (0) 2025.03.28