본문 바로가기

C++ 공부

C++ 공부 8일차(STL, 컨테이너, 벡터, 맵, 알고리즘, 반복자)

STL

STL(Standard Template Library)은 표준 템플릿 라이브러리로 C++ 표준 라이브러리의 일부로, 컨테이너, 알고리즘, 반복자 등의 템플릿 기반 구성 요소를 포함한다.(C++에서 제공하는 데이터 의존하지 않고 사용할 수 있는 라이브러리)

STL을 활용하면 다양한 자료구조와 알고리즘을 직접 구현하지 않고도 사용할 수 있다.

컨테이너 - 데이터를 담는다. / 알고리즘 - 여러가지 동작 / 반복자 - 컨테이너와 알고리즘에 대 세부사항을 몰라도 동일한 문법으로 사용할 수 있도록 해주는 문법.

컨테이너

데이터를 담는 자료구조를 말한다. 데이터를 담는 방식이나 제공하는 메서드에 따라 여러 가지 컨테이너를 제공한다.

 

1. 모든 컨테이너는 템플릿으로 구현되어 있으므로, 다양한 타입의 데이터를 저장할 수 있습니다.

2. 모든 컨테이너는 메모리 관리를 내부적으로 합니다. 즉 메모리 해제를 직접 고려하지 않아도 됩니다.(new, delete 사용 안함)

3. 대부분 컨테이너는 반복자를 제공합니다. 따라서 내부 구현을 몰라도 동일한 방식으로 컨테이너를 순회할 수 있습니다.

사용자는 컨테이너의 큰 특징만 알면 된다.

벡터

벡터는 배열과 매우 유사한 컨테이너다.

 

1. 템플릿 클래스로 구현되어 특정 타입에 종속되지 않습니다.

2. 삽입되는 원소 개수에 따라 내부 배열의 크기가 자동으로 조정됩니다.

3. 임의 접근이 가능합니다. (인덱스를 통해 특정 위치에 접근)

4. 삽입 / 삭제는 맨 뒤에 하는 게 좋습니다. (중간 삽입 / 삭제는 배열 복사가 필요하므로 비효율적)

중간 값에 삽입 또는 삭제를 한다면 원래 있던 원소들이 이동할 때 값을 복사하여 이동해야 하므로 비효율적이다.

벡터의 선언

타입만 명시해서 선언하는 방법이 있고, 초기값까지 같이 선언하는 경우도 있다.

 

1. 빈 벡터를 선언하거나 특정 값으로 초기화하는 코드입니다.

vec는 빈 벡터이므로 크기가 0이고, vec2의 크기는 5이며 모든 값이 10이다.

#include <vector>
using namespace std;

// 1. 기본 생성 및 초기화 없이 선언
vector<int> vec1;

// 2. 특정 크기와 초기값으로 벡터 선언
vector<int> vec2(5, 10); // 크기 5, 모든 원소가 10으로 초기화

//메인 함수 생략

2. 초기화 리스트를 사용하여 벡터를 선언하는 코드이다.

특정 값으로 벡터를 초기화할 때 자주 사용됩니다. 초기화하는 원소의 개수가 적을 때 주로 활용합니다.

#include <vector>
using namespace std;

// 3. 리스트 초기화로 벡터 선언
vector<int> vec3 = {1, 2, 3, 4, 5};

//메인 함수 생략

3. 다른 벡터의 복사하거나 대입하는 방법도 있습니다.

기존에 생성된 벡터의 복사본을 만들 때 많이 사용합니다.

#include <vector>
using namespace std;

// 다른 벡터를 기반으로 복사 초기화
vector<int> vec3 = {1, 2, 3, 4, 5};
vector<int> vec4(vec3); // vec3의 복사본 생성
//vector<int> vec4 = vec3 하면 대입이 됨
//메인 함수 생략

4. 2차원 배열처럼 벡터를 사용하려면, 벡터의 타입을 벡터로 하면 됩니다.

#include <vector>
using namespace std;

// 2차원 벡터 초기화
vector<vector<int>> vec2D(3, vector<int>(4, 7)); // 3x4 행렬, 모든 원소가 7로 초기화

//메인 함수 생략

벡터의 동작

벡터에서 제공하는 메서드 중에 많이 사용되는 메서드에 대해 알아보자.

 

1. push_back

벡터의 맨 끝에 원소를 추가하는 메서드입니다.

원소의 개수가 늘어남에 따라 크기는 자동으로 증가하므로, 별도의 메모리 관리를 신경 쓸 필요가 없습니다.

#include <iostream>
#include <vector>
using namespace std;

int main()
{
    vector<int> vec; // vec 벡터 선언;
    vec.push_back(10);
    vec.push_back(20);
    vec.push_back(30);

    cout << "Vector after push_back: ";
    for (int num : vec) // num에 vec의 왼쪽 원소부터 차례대로 넣으면서 for문 실행
    {
        cout << num << " ";
    }
    return 0;
}
// 출력: Vector after push_back: 10 20 30

2. pop_back

벡터의 맨 끝에 원소를 제거하는 메서드입니다. 맨 끝 원소가 제거되면 벡터 크기가 자동으로 줄어듭니다.

push_back 잘못됨. pop_back이 맞음.

#include <iostream>
#include <vector>
using namespace std;

int main() {
    vector<int> vec = {10, 20, 30};
    vec.pop_back();  // 마지막 요소(30) 제거

    cout << "Vector after pop_back: ";
    for (int num : vec)
    {
        cout << num << " ";
    }
    return 0;
}
// 출력: Vector after pop_back: 10 20

3. size

현재 벡터의 크기(원소 개수)를 확인할 때 사용하는 메서드입니다.

보통 벡터의 전체 원소를 대상으로 반복문을 돌릴 때 유용하게 쓰입니다.

#include <iostream>
#include <vector>
using namespace std;

int main()
{
    vector<int> vec = {10, 20, 30};
    cout << "Size of vector: " << vec.size() << endl;

    vec.push_back(40); // 맨 끝에 40 원소 추가
    cout << "Size after push_back: " << vec.size() << endl;

    vec.pop_back(); // 맨 끝에 추가됐던 40 원소 제거
    cout << "Size after pop_back: " << vec.size() << endl;

    return 0;
}
// 출력:
// Size of vector: 3
// Size after push_back: 4
// Size after pop_back: 3

4. erase(되도록 push_back, pop_back 사용하기)

특정 위치(또는 구간)의 원소를 제거하는 함수입니다.

벡터는 내부적으로 배열을 사용하므로, 중간 원소를 삭제할 때, 많은 원소를 옮겨야 할 수 있습니다.

따라서 시간 복잡도가 커질 수 있으므로, 자주 사용하지 않는 것이 좋습니다.(벡터의 성능이 떨어짐, 비효율적)

컨테이너들의 begin 메서드는 시작 주소를 의미한다.

erase는 인자를 하나 또는 두 개 받을 수 있는데 하나를 받으면 그 위치의 원소를 제거하는 거고

두 개면 (a,b)일 때 a <= x < b에서 x에 해당하는 원소들이 삭제된다.

#include <iostream>
#include <vector>
using namespace std;

int main()
{
    vector<int> vec = {10, 20, 30, 40, 50};

    // 두 번째 요소 제거 (index 1)
    vec.erase(vec.begin() + 1);

    cout << "Vector after erasing second element: ";
    for (int num : vec)
    {
        cout << num << " ";
    }
    cout << endl;

    // 위에서 두 번째 원소가 삭제된 10, 30, 40, 50 상태에서 2~3번째 원소 제거
    vec.erase(vec.begin() + 1, vec.begin() + 3);

    cout << "Vector after erasing range: ";
    for (int num : vec)
    {
        cout << num << " ";
    }
    return 0;
}
// 출력:
// Vector after erasing second element: 10 30 40 50
// Vector after erasing range: 10 50

맵은 특정 키를 사용하여 값을 검색하는 기능을 제공하는 컨테이너이다.(연관 컨테이너, 키와 값이 쌍으로 구성됨)

 

1. 키 - 값 쌍은 pair<const Key, Value> 형태로 저장된다.

2. 키 값을 기준으로 내부 데이터가 자동으로 정렬이 된다.

3. 중복된 키 값은 허용되지 않는다.

맵의 선언

맵을 선언할 때는 키 - 값 쌍을 저장하기 위해 키 타입과 값 타입 두 가지를 지정해야 합니다.

이 두 타입은 동일할 수도 있고, 서로 다를 수도 있으며, 키 타입은 비교 연산이 가능해야 합니다.

// 키 값 타입이 다를 경우

#include <iostream>
#include <map>

using namespace std;

// 정수 키와 문자열 값을 저장하는 map 예제
int main()
{
    map<int, string> studentMap;

    // 요소 추가, 특정 키(101)에 해당하는 값(Alice)을 넣어주는 작업
    studentMap[101] = "Alice";
    studentMap[102] = "Bob";
    studentMap[103] = "Charlie";

    // 요소 출력 key가 first, value가 second
    for (const auto& pair : studentMap)
    {
        cout << "ID: " << pair.first << ", Name: " << pair.second << endl;
    }

    return 0;
}
/*
출력 결과:
ID: 101, Name: Alice
ID: 102, Name: Bob
ID: 103, Name: Charlie
*/
// 키 값 타입이 같을 경우

#include <iostream>
#include <map>

using namespace std;

// 문자열 키와 문자열 값을 저장하는 map 예제
int main()
{
    map<string, string> countryMap;

    // 요소 추가
    countryMap["KR"] = "Korea";
    countryMap["US"] = "United States";
    countryMap["JP"] = "Japan";

    // 요소 출력
    for (const auto& pair : countryMap)
    {
        cout << "Country Code: " << pair.first << ", Country Name: " << pair.second << endl;
    }

    return 0;
}
/*
출력 결과:
Country Code: JP, Country Name: Japan
Country Code: KR, Country Name: Korea
Country Code: US, Country Name: United States
*/

맵의 동작

1. map은 key 순으로 오름차순 정렬된다.

사용자가 별도로 정렬을 수행하지 않아도, 삽입 및 삭제가 이루어질 때마다 내부적으로 정렬 상태를 유지한다.

#include <iostream>
#include <map>

using namespace std;

int main()
{
    map<int, string> myMap;

    // 정렬되지 않은 순서로 요소 추가
    myMap[20] = "Banana";
    myMap[5] = "Apple";
    myMap[15] = "Cherry";
    myMap[10] = "Grapes";

    // 요소 출력 (자동으로 key 기준 오름차순 정렬)
    for (const auto& pair : myMap)
    {
        cout << "Key: " << pair.first << ", Value: " << pair.second << endl;
    }

    return 0;
}

/*
출력 결과:
Key: 5, Value: Apple
Key: 10, Value: Grapes
Key: 15, Value: Cherry
Key: 20, Value: Banana
*/

2. insert() (= 맵에 데이터를 추가하는 방법은 여러가지다.)

make_pair()을 이용하여 pair 객체를 생성한 후 insert 함수를 사용할 수 있다.

또한 { } 를 활용한 방법이나 [ ] 를 사용하여 값을 추가할 수도 있다.

// insert와 make_pair 사용해서 데이터 추가하기

#include <iostream>
#include <map>

using namespace std;

int main()
{
    map<int, string> myMap;

    // make_pair()를 사용하여 insert()
    myMap.insert(make_pair(1, "Apple"));
    myMap.insert(make_pair(2, "Banana"));
    myMap.insert(make_pair(3, "Cherry"));

    // 출력
    for (const auto& pair : myMap)
    {
        cout << "Key: " << pair.first << ", Value: " << pair.second << endl;
    }

    return 0;
}
/*
출력 결과:
Key: 1, Value: Apple
Key: 2, Value: Banana
Key: 3, Value: Cherry
*/
// insert와 { } 사용한 데이터 추가

#include <iostream>
#include <map>

using namespace std;

int main()
{
    map<int, string> myMap;

    // {}를 사용하여 insert()
    myMap.insert({4, "Dog"});
    myMap.insert({5, "Elephant"});
    myMap.insert({6, "Frog"});

    // 출력
    for (const auto& pair : myMap)
    {
        cout << "Key: " << pair.first << ", Value: " << pair.second << endl;
    }

    return 0;
}
/*
출력 결과:
Key: 4, Value: Dog
Key: 5, Value: Elephant
Key: 6, Value: Frog
*/
// [ ]연산자를 사용한 데이터 추가

#include <iostream>
#include <map>

using namespace std;

int main()
{
    map<int, string> myMap;

    // [] 연산자로 값 추가
    myMap[7] = "Giraffe";
    myMap[8] = "Horse";
    myMap[9] = "Iguana";

    // 출력
    for (const auto& pair : myMap)
    {
        cout << "Key: " << pair.first << ", Value: " << pair.second << endl;
    }

    return 0;
}
/*
출력 결과:
Key: 7, Value: Giraffe
Key: 8, Value: Horse
Key: 9, Value: Iguana
*/

3. find()

find 메서드를 사용하면 특정 키가 map에 존재하는지 확인할 수 있다.

find는 키가 존재하면 해당 키의 이터레이터를 반환하고, 존재하지 않으면 map.end()를 반환합니다.

(이터레이터의 자세 개념은 나중에 나옴, 간단하게 위치)

#include <iostream>
#include <map>

using namespace std;

int main()
{
    map<int, string> myMap =
    {
        {1, "Apple"},
        {2, "Banana"},
        {3, "Cherry"}
    };

    int key = 2;
    auto it = myMap.find(key); // 키 2를 찾기

    if (it != myMap.end()) // 키가 있으면
    {
        cout << "Found! Key: " << it->first << ", Value: " << it->second << endl;
    } else {
        cout << "Key " << key << " not found!" << endl;
    }

    return 0;
}
/*
출력 결과:
Found! Key: 2, Value: Banana
*/

4. size()

맵에 키 - 값 쌍의 개수를 반환하는 함수이다.

#include <iostream>
#include <map>

using namespace std;

int main()
{
    map<int, string> myMap;

    // 요소 추가
    myMap[1] = "Apple";
    myMap[2] = "Banana";
    myMap[3] = "Cherry";

    // 현재 크기 출력
    cout << "Map size: " << myMap.size() << endl;

    return 0;
}
/*
출력 결과:
Map size: 3
*/

5. erase(key)

맵의 특정 key를 가진 요소만 삭제한다.

#include <iostream>
#include <map>

using namespace std;

int main()
{
    map<int, string> myMap =
    {
        {1, "Apple"},
        {2, "Banana"},
        {3, "Cherry"}
    };

    cout << "Before erase, size: " << myMap.size() << endl;

    // 특정 키 삭제
    myMap.erase(2);

    cout << "After erase(2), size: " << myMap.size() << endl;

    // 남은 요소 출력
    for (const auto& pair : myMap)
    {
        cout << "Key: " << pair.first << ", Value: " << pair.second << endl;
    }

    return 0;
}
/*
출력 결과:
Before erase, size: 3
After erase(2), size: 2
Key: 1, Value: Apple
Key: 3, Value: Cherry
*/

6. clear

맵에 있는 모든 원소를 삭제하는 함수입니다. clear는 맵뿐 아니라 대부분 컨테이너에 존재합니다.

#include <iostream>
#include <map>

using namespace std;

int main()
{
    map<int, string> myMap =
    {
        {1, "Apple"},
        {2, "Banana"},
        {3, "Cherry"}
    };

    cout << "Before clear, size: " << myMap.size() << endl;

    // 모든 요소 삭제
    myMap.clear();

    cout << "After clear, size: " << myMap.size() << endl;

    return 0;
}
/*
출력 결과:
Before clear, size: 3
After clear, size: 0
*/

알고리즘

sort

컨테이너 내부의 데이터를 정렬하는 함수이다.

기본 타입(int, double 등)의 경우 사용자 정렬 함수가 없으면 오름차순으로 정렬됩니다.

또한 사용자 정렬 함수를 정의할 수도 있습니다.

 

사용자 정렬 함수 comp(a, b) 구현 시 알아둬야 할 점이 있다.

1. 현재 컨테이너에서 첫번째 인자 a가 앞에 있는 원소를 의미한다.

2. comp(a ,b) 가 true 이면 a와 b의 순서는 유지됩니다. 만약 false인 경우 a와 b의 순서를 바꿉니다.

// 기본타입 배열 정렬(사용자 정렬 기준 없음)

#include <iostream>
#include <algorithm> // sort 함수 포함

using namespace std;

int main() 
{
    int arr[] = {5, 2, 9, 1, 5, 6};
    int size = sizeof(arr) / sizeof(arr[0]); // 배열의 크기 구함

    // 오름차순 정렬
    sort(arr, arr + size);

    // 결과 출력
    for (int i = 0; i < size; i++)
    {
        cout << arr[i] << " ";
    }
    return 0;
}
// 출력 : 1 2 5 5 6 9
// 기본타입 배열 정렬(사용자 정렬 기준 있음)

#include <iostream>
#include <algorithm> // sort 함수 포함

using namespace std;

bool compare(int a, int b)
{
    return a > b; // 내림차순
}

int main() 
{
    int arr[] = {5, 2, 9, 1, 5, 6};
    int size = sizeof(arr) / sizeof(arr[0]);

    // 내림차순 정렬
    sort(arr, arr + size, compare);

    // 결과 출력
    for (int i = 0; i < size; i++)
    {
        cout << arr[i] << " ";
    }
    return 0;
}
// 출력 : 9 6 5 5 2 1
// 기본타입 벡터 정렬(정렬기준 없음)

#include <iostream>
#include <vector>
#include <algorithm> // sort 함수 포함

using namespace std;

int main() 
{
    vector<int> vec = {5, 2, 9, 1, 5, 6}; // 벡터 선언

    // 오름차순 정렬
    // STL에서 범위는 시작은 포함, 끝은 미포함(미만)으로 함
    sort(vec.begin(), vec.end()); // vec.end는 끝의 다음구역이 지정됨

    // 결과 출력
    for (int num : vec) 
    {
        cout << num << " ";
    }
    return 0;
}
// 출력 : 1 2 5 5 6 9

vec.begin과 end 그림

// 기본타입 벡터 정렬(정렬기준 있음)

#include <iostream>
#include <vector>
#include <algorithm> // sort 함수 포함
using namespace std;

bool compare(int a, int b) 
{
    return a > b; // 내림차순
}

int main()
{
    vector<int> vec = {5, 2, 9, 1, 5, 6};

    // 내림차순 정렬
    sort(vec.begin(), vec.end(), compare);

    // 결과 출력
    for (int num : vec)
    {
        cout << num << " ";
    }
    return 0;
}
// 출력 : 9 6 5 5 2 1
// class타입 벡터 정렬

#include <iostream>
#include <vector>
#include <algorithm> // sort 함수 포함

using namespace std;

class Person // 사용자가 정의한 class는 C++ 라이브러리에 정보가 없음
{
private:
    string name;
    int age;

public:
    // 생성자
    Person(string name, int age) : name(name), age(age) 
    {}

    // Getter 함수
    string getName() const { return name; }
    int getAge() const { return age; }
};

// 사용자 정의 클래스는 C++에서 자동으로 대소비교가 불가능해서 정렬기준이 필수
// 다중 기준 정렬 함수 (나이 오름차순 → 이름 오름차순)
bool compareByAgeAndName(const Person& a, const Person& b)
{
    if (a.getAge() == b.getAge()) // 나이가 같다면
    {
        return a.getName() < b.getName(); // 이름 오름차순
    }
    return a.getAge() < b.getAge(); // 나이 오름차순
}

int main() 
{
    vector<Person> people = 
    {
        Person("Alice", 30),
        Person("Bob", 25),
        Person("Charlie", 35),
        Person("Alice", 25)
    };

    // 나이 → 이름 순으로 정렬
    sort(people.begin(), people.end(), compareByAgeAndName);

    // 결과 출력
    for (const Person& person : people)
    {
        cout << person.getName() << " (" << person.getAge() << ")" << endl;
    }
    return 0;
}
/* 출력 :
Alice (25)
Bob (25)
Alice (30)
Charlie (35)
*/

find

컨테이너 내부에서 특정 원소를 찾아 해당 원소의 반복자를 반환하는 함수이다.

1. find(first, last, 찾을 값) -> first <= 찾을 값 < last

2. 원소를 찾은 경우 해당 원소의 반복자를 반환한다.

3. 원소를 찾지 못한 경우 last 반복자를 반환한다.

// 벡터에서 특정 값 찾기

#include <iostream>
#include <vector>
#include <algorithm> // find 함수 포함

using namespace std;

int main() 
{
    vector<int> vec = {10, 20, 30, 40, 50};

    // 특정 값 30을 찾음
    auto it = find(vec.begin(), vec.end(), 30);

    if (it != vec.end()) // 특정 값을 찾았다면 
    {	// it(특정 값 위치)에서 vec.begin(벡터의 시작 위치)을 빼면 찾은 인덱스 값이 나옴
        cout << "값 30이 벡터에서 발견됨, 위치: " << (it - vec.begin()) << endl;
    } 
    else 
    {
        cout << "값 30이 벡터에 없음" << endl;
    }
    return 0;
}
// 출력 : 값 30이 벡터에서 발견됨, 위치: 2
// 배열에서 특정 값 찾기

#include <iostream>
#include <algorithm> // find 함수 포함

using namespace std;

int main()
{
    int arr[] = {1, 2, 3, 4, 5};
    int size = sizeof(arr) / sizeof(arr[0]);

    // 특정 값 4를 찾음
    auto it = find(arr, arr + size, 4);

    if (it != arr + size) 
    {
        cout << "값 4가 배열에서 발견됨, 위치: " << (it - arr) << endl;
    }
    else 
    {
        cout << "값 4가 배열에 없음" << endl;
    }
    return 0;
}
// 출력 : 값 4가 배열에서 발견됨, 위치: 3
// 문자열에서 특정 문자 찾기

#include <iostream>
#include <algorithm> // find 함수 포함
#include <string>
using namespace std;

int main()
{
    string str = "hello world";

    // 문자 'o' 찾기
    auto it = find(str.begin(), str.end(), 'o');

    if (it != str.end()) 
    {
        cout << "문자 'o'가 문자열에서 발견됨, 위치: " << (it - str.begin()) << endl;
    } 
    else 
    {
        cout << "문자 'o'가 문자열에 없음" << endl;
    }
    return 0;
}
// 출력 : 문자 'o'가 문자열에서 발견됨, 위치: 4

반복자

컨테이너의 내부 구조는 서로 다르지만, 대부분 알고리즘을 동일한 코드를 활용해서 사용할 수 있었습니다.

즉 컨테이너 구현 방식에 의존하지 않고(내부 구현을 몰라도) 알고리즘을 활용하는데 문제가 없습니다.

이는 반복자를 기반으로 알고리즘이 동작하기 때문입니다.

반복자는 컨테이너의 요소에 대한 일관된 접근 방법을 제공하므로, 알고리즘이 특정 컨테이너의 내부 구현과 무관하게 동작할 수 있습니다.

순방향 반복자

순방향 반복자는 앞에서부터 뒤로 순차적으로 순회하는 반복자다.

begin()은 컨테이너의 첫 번째 원소를 가리키는 반복자다.

end()는 컨테이너의 마지막 원소 다음을 가리키는 반복자다.

end()를 마지막 원소 다음을 가리키도록 정한 이유는 일관된 반복 구조 유지와 탐색 실패를 쉽게 표현하기 위해서 이다.

// 벡터 순방향 반복자 사용예시

#include <vector>
#include <iostream>
using namespace std;

int main() 
{
    vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    
    // 순방향 반복자를 사용해 짝수만 출력
    for (auto it = numbers.begin(); it != numbers.end(); ++it) 
    {
        if (*it % 2 == 0) 
        {
            cout << *it << " ";
        }
    }
    return 0;
}
// 출력: 2 4 6 8 10
// 맵 순방향 반복자 사용 예시

#include <map>
#include <iostream>
using namespace std;

int main() 
{
    map<string, int> scores =
    {
    {"Alice", 90}, {"Bob", 85}, {"Charlie", 88}
    };
    
    // 순방향 반복자를 사용해 맵의 키-값 쌍 출력
    for (auto it = scores.begin(); it != scores.end(); ++it)
    {
        cout << it->first << ": " << it->second << endl;
    }
    return 0;
}
// 출력:
// Alice: 90
// Bob: 85
// Charlie: 88
// 문자열에서 순방향 반복자 사용 예시

#include <vector>
#include <string>
#include <algorithm>
#include <iostream>
using namespace std;

int main()
{
    vector<string> words = {"apple", "banana", "cherry", "date"};

    string target = "cherry";

    auto it = find(words.begin(), words.end(), target);

    if (it != words.end()) 
    {	// distance는 두 사이의 거리(인덱스 차이)를 구한다. it - words.begin()과 동일
        cout << "Word \"" << target << "\" found at index " << distance(words.begin(), it) << endl;
    }
    else
    {
        cout << "Word \"" << target << "\" not found." << endl;
    }

    return 0;
}
// 출력: Word "cherry" found at index 2

역방향 반복자

컨테이너의 마지막 원소부터 첫 번째 원소까지 역순으로 순회할 수 있도록 해주는 반복자다.

rbegin()은 컨테이너의 마지막 원소를 가리키는 역방향 반복자다.

rend() 컨테이너의 첫 번째 원소 이전을 가리키는 역방향 반복자다.

컨테이너의 첫 번째 원소까지 탐색했지만 원하는 원소를 찾지 못한 경우, rend()를 반환하여 탐색 실패를 명확하게 표현할 수 있다.

// 벡터 역방향 반복자 사용 예시

#include <vector>
#include <iostream>
using namespace std;

int main() 
{
    vector<int> numbers = {10, 15, 20, 25, 30};

    // 역방향 반복자로 짝수만 출력
    for (auto it = numbers.rbegin(); it != numbers.rend(); ++it)
    {
        if (*it % 2 == 0)
        {
            cout << *it << " ";
        }
    }

    return 0;
}
// 출력: 30 20 10
// 맵 역방향 반복자 사용 예시

#include <map>
#include <iostream>
using namespace std;

int main()
{
    map<string, int> scores = {{"Alice", 90}, {"Bob", 85}, {"Charlie", 88}};

    // 역방향 반복자로 값이 88 이상인 항목만 출력
    for (auto it = scores.rbegin(); it != scores.rend(); ++it)
    {
        if (it->second >= 88) // it의 value가 88이상일 때
        {
            cout << it->first << ": " << it->second << endl;
        }
    }

    return 0;
}
// 출력:
// Charlie: 88
// Alice: 90
// 문자열에서 역방향 반복자를 사용한 예시

#include <vector>
#include <string>
#include <algorithm>
#include <iostream>
using namespace std;

int main()
{
    vector<string> words = {"apple", "banana", "cherry", "date"};

    string target = "banana";

    auto it = find(words.rbegin(), words.rend(), target);

    if (it != words.rend()) 
    {
        cout << "Word \"" << target << "\" found at reverse index " 
             << distance(words.rbegin(), it) << " (from the back)" << endl;
        cout << "Word \"" << target << "\" found at forward index " 
             << distance(words.begin(), it.base()) - 1 << " (from the front)" << endl;
    }
    else
    {
        cout << "Word \"" << target << "\" not found." << endl;
    }

    return 0;
}
// 출력:
// Word "banana" found at reverse index 2 (from the back)
// Word "banana" found at forward index 1 (from the front)

 

숙제 : 반복자를 활용하여 각 컨테이너를 순회하기