STL 알고리즘과 반복자

STL 알고리즘과 반복자

1. 반복자 (Iterator)

반복자는 컨테이너의 요소를 가리키는 포인터 같은 객체입니다.

반복자 종류

종류 설명 예시 컨테이너
입력 반복자 읽기만 가능, 한 방향 istream_iterator
출력 반복자 쓰기만 가능, 한 방향 ostream_iterator
순방향 반복자 읽기/쓰기, 한 방향 forward_list
양방향 반복자 읽기/쓰기, 양방향 list, set, map
임의 접근 반복자 모든 연산, 임의 접근 vector, deque, array

반복자 기본 사용

#include <iostream>
#include <vector>

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};

    // begin(), end()
    std::vector<int>::iterator it = v.begin();
    std::cout << *it << std::endl;  // 1

    ++it;
    std::cout << *it << std::endl;  // 2

    // 순회
    for (auto it = v.begin(); it != v.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;

    return 0;
}

const 반복자

#include <iostream>
#include <vector>

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};

    // const_iterator: 읽기만 가능
    for (std::vector<int>::const_iterator it = v.cbegin();
         it != v.cend(); ++it) {
        std::cout << *it << " ";
        // *it = 10;  // 에러! 수정 불가
    }

    return 0;
}

역방향 반복자

#include <iostream>
#include <vector>

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};

    // rbegin(), rend()
    for (auto it = v.rbegin(); it != v.rend(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;  // 5 4 3 2 1

    return 0;
}

2. 람다 표현식

익명 함수를 간결하게 정의합니다.

기본 문법

[캡처](매개변수) -> 반환타입 { 본문 }

예시

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

int main() {
    // 기본 람다
    auto add = [](int a, int b) {
        return a + b;
    };
    std::cout << add(3, 5) << std::endl;  // 8

    // 반환 타입 명시
    auto divide = [](double a, double b) -> double {
        return a / b;
    };

    // 알고리즘과 함께
    std::vector<int> v = {3, 1, 4, 1, 5, 9};
    std::sort(v.begin(), v.end(), [](int a, int b) {
        return a > b;  // 내림차순
    });

    return 0;
}

캡처

#include <iostream>

int main() {
    int x = 10;
    int y = 20;

    // 값 캡처 (복사)
    auto f1 = [x]() { return x; };

    // 참조 캡처
    auto f2 = [&x]() { x++; };

    // 모든 변수 값 캡처
    auto f3 = [=]() { return x + y; };

    // 모든 변수 참조 캡처
    auto f4 = [&]() { x++; y++; };

    // 혼합
    auto f5 = [=, &x]() {  // y는 값, x는 참조
        x++;
        return y;
    };

    f2();
    std::cout << x << std::endl;  // 11

    return 0;
}

mutable 람다

#include <iostream>

int main() {
    int x = 10;

    // 값 캡처는 기본적으로 const
    auto f = [x]() mutable {  // mutable로 수정 가능
        x++;
        return x;
    };

    std::cout << f() << std::endl;  // 11
    std::cout << x << std::endl;    // 10 (원본은 변경 안 됨)

    return 0;
}

3. 기본 알고리즘

<algorithm> 헤더를 포함해야 합니다.

for_each

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

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};

    std::for_each(v.begin(), v.end(), [](int n) {
        std::cout << n * 2 << " ";
    });
    std::cout << std::endl;  // 2 4 6 8 10

    return 0;
}

transform

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

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};
    std::vector<int> result(v.size());

    // 각 요소를 변환
    std::transform(v.begin(), v.end(), result.begin(),
                   [](int n) { return n * n; });

    for (int n : result) {
        std::cout << n << " ";
    }
    std::cout << std::endl;  // 1 4 9 16 25

    return 0;
}

4. 검색 알고리즘

find

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

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};

    auto it = std::find(v.begin(), v.end(), 3);
    if (it != v.end()) {
        std::cout << "찾음: " << *it << std::endl;
        std::cout << "인덱스: " << std::distance(v.begin(), it) << std::endl;
    }

    return 0;
}

find_if

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

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};

    // 조건을 만족하는 첫 요소
    auto it = std::find_if(v.begin(), v.end(),
                           [](int n) { return n > 3; });

    if (it != v.end()) {
        std::cout << "첫 번째 > 3: " << *it << std::endl;  // 4
    }

    return 0;
}

count / count_if

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

int main() {
    std::vector<int> v = {1, 2, 2, 3, 2, 4, 5};

    // 특정 값 개수
    int c1 = std::count(v.begin(), v.end(), 2);
    std::cout << "2의 개수: " << c1 << std::endl;  // 3

    // 조건 만족 개수
    int c2 = std::count_if(v.begin(), v.end(),
                           [](int n) { return n % 2 == 0; });
    std::cout << "짝수 개수: " << c2 << std::endl;  // 4

    return 0;
}

정렬된 범위에서만 사용합니다.

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

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};  // 정렬된 상태

    bool found = std::binary_search(v.begin(), v.end(), 3);
    std::cout << "3 있음: " << found << std::endl;  // 1

    return 0;
}

5. 정렬 알고리즘

sort

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

int main() {
    std::vector<int> v = {3, 1, 4, 1, 5, 9, 2, 6};

    // 오름차순 (기본)
    std::sort(v.begin(), v.end());

    // 내림차순
    std::sort(v.begin(), v.end(), std::greater<int>());

    // 사용자 정의 비교
    std::sort(v.begin(), v.end(), [](int a, int b) {
        return a > b;  // 내림차순
    });

    return 0;
}

partial_sort

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

int main() {
    std::vector<int> v = {3, 1, 4, 1, 5, 9, 2, 6};

    // 상위 3개만 정렬
    std::partial_sort(v.begin(), v.begin() + 3, v.end());

    for (int n : v) {
        std::cout << n << " ";
    }
    // 1 1 2 ... (앞 3개만 정렬됨)

    return 0;
}

nth_element

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

int main() {
    std::vector<int> v = {3, 1, 4, 1, 5, 9, 2, 6};

    // 3번째 요소를 제자리에 (정렬되면 있을 위치)
    std::nth_element(v.begin(), v.begin() + 3, v.end());

    std::cout << "3번째 요소: " << v[3] << std::endl;

    return 0;
}

6. 수정 알고리즘

copy

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

int main() {
    std::vector<int> src = {1, 2, 3, 4, 5};
    std::vector<int> dest(5);

    std::copy(src.begin(), src.end(), dest.begin());

    return 0;
}

fill

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

int main() {
    std::vector<int> v(5);

    std::fill(v.begin(), v.end(), 42);

    for (int n : v) {
        std::cout << n << " ";
    }
    std::cout << std::endl;  // 42 42 42 42 42

    return 0;
}

replace

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

int main() {
    std::vector<int> v = {1, 2, 3, 2, 4, 2, 5};

    // 2를 100으로 교체
    std::replace(v.begin(), v.end(), 2, 100);

    for (int n : v) {
        std::cout << n << " ";
    }
    std::cout << std::endl;  // 1 100 3 100 4 100 5

    return 0;
}

remove / erase

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

int main() {
    std::vector<int> v = {1, 2, 3, 2, 4, 2, 5};

    // remove는 실제로 삭제하지 않음
    auto newEnd = std::remove(v.begin(), v.end(), 2);

    // erase와 함께 사용 (erase-remove idiom)
    v.erase(newEnd, v.end());

    for (int n : v) {
        std::cout << n << " ";
    }
    std::cout << std::endl;  // 1 3 4 5

    return 0;
}

reverse

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

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};

    std::reverse(v.begin(), v.end());

    for (int n : v) {
        std::cout << n << " ";
    }
    std::cout << std::endl;  // 5 4 3 2 1

    return 0;
}

unique

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

int main() {
    std::vector<int> v = {1, 1, 2, 2, 2, 3, 3, 4};

    // 연속된 중복 제거 (정렬 필요)
    auto newEnd = std::unique(v.begin(), v.end());
    v.erase(newEnd, v.end());

    for (int n : v) {
        std::cout << n << " ";
    }
    std::cout << std::endl;  // 1 2 3 4

    return 0;
}

7. 수치 알고리즘

<numeric> 헤더를 포함합니다.

accumulate

#include <iostream>
#include <vector>
#include <numeric>

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};

    // 합계
    int sum = std::accumulate(v.begin(), v.end(), 0);
    std::cout << "합: " << sum << std::endl;  // 15

    // 곱
    int product = std::accumulate(v.begin(), v.end(), 1,
                                  std::multiplies<int>());
    std::cout << "곱: " << product << std::endl;  // 120

    // 사용자 정의
    int sumSquares = std::accumulate(v.begin(), v.end(), 0,
        [](int acc, int n) { return acc + n * n; });
    std::cout << "제곱합: " << sumSquares << std::endl;  // 55

    return 0;
}

iota

#include <iostream>
#include <vector>
#include <numeric>

int main() {
    std::vector<int> v(10);

    // 연속된 값으로 채우기
    std::iota(v.begin(), v.end(), 1);

    for (int n : v) {
        std::cout << n << " ";
    }
    std::cout << std::endl;  // 1 2 3 4 5 6 7 8 9 10

    return 0;
}

8. 집합 알고리즘

정렬된 범위에서만 작동합니다.

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

int main() {
    std::vector<int> a = {1, 2, 3, 4, 5};
    std::vector<int> b = {3, 4, 5, 6, 7};
    std::vector<int> result;

    // 합집합
    std::set_union(a.begin(), a.end(), b.begin(), b.end(),
                   std::back_inserter(result));
    // result: 1 2 3 4 5 6 7

    result.clear();

    // 교집합
    std::set_intersection(a.begin(), a.end(), b.begin(), b.end(),
                          std::back_inserter(result));
    // result: 3 4 5

    result.clear();

    // 차집합
    std::set_difference(a.begin(), a.end(), b.begin(), b.end(),
                        std::back_inserter(result));
    // result: 1 2

    return 0;
}

9. min/max 알고리즘

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

int main() {
    std::vector<int> v = {3, 1, 4, 1, 5, 9, 2, 6};

    // 최소/최대 요소
    auto minIt = std::min_element(v.begin(), v.end());
    auto maxIt = std::max_element(v.begin(), v.end());

    std::cout << "최소: " << *minIt << std::endl;
    std::cout << "최대: " << *maxIt << std::endl;

    // 둘 다
    auto [minEl, maxEl] = std::minmax_element(v.begin(), v.end());
    std::cout << *minEl << " ~ " << *maxEl << std::endl;

    // 값 비교
    std::cout << std::min(3, 5) << std::endl;  // 3
    std::cout << std::max(3, 5) << std::endl;  // 5

    return 0;
}

10. all_of / any_of / none_of

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

int main() {
    std::vector<int> v = {2, 4, 6, 8, 10};

    // 모두 만족?
    bool all = std::all_of(v.begin(), v.end(),
                           [](int n) { return n % 2 == 0; });
    std::cout << "모두 짝수: " << all << std::endl;  // 1

    // 하나라도 만족?
    bool any = std::any_of(v.begin(), v.end(),
                           [](int n) { return n > 5; });
    std::cout << "하나라도 > 5: " << any << std::endl;  // 1

    // 아무것도 만족 안 함?
    bool none = std::none_of(v.begin(), v.end(),
                             [](int n) { return n < 0; });
    std::cout << "음수 없음: " << none << std::endl;  // 1

    return 0;
}

11. 요약

알고리즘 용도
find, find_if 검색
count, count_if 개수 세기
sort, partial_sort 정렬
binary_search 이진 검색
transform 변환
for_each 각 요소에 함수 적용
copy, fill, replace 수정
remove, unique 제거
reverse 역순
accumulate 누적
min_element, max_element 최소/최대

다음 단계

12_Templates.md에서 템플릿을 배워봅시다!

to navigate between lessons