프로그래밍/C++

C++ 표준 라이브러리: STL 컨테이너, 반복자, 알고리즘, 함수 객체의 심화 활용

shimdh 2025. 2. 2. 13:12
728x90

1. STL 컨테이너: 데이터를 저장하고 관리하는 도구

STL 컨테이너는 데이터를 저장하고 관리하는 데 사용되는 클래스 템플릿입니다. 각 컨테이너는 고유한 특성을 가지고 있으며, 상황에 맞게 적절한 컨테이너를 선택하는 것이 중요합니다. STL 컨테이너는 크게 시퀀스 컨테이너연관 컨테이너로 나눌 수 있습니다.

1.1 주요 STL 컨테이너 종류

1.1.1 벡터 (vector)

  • 특징: 동적 배열로, 요소를 추가하거나 삭제할 때 유연성을 제공합니다.

  • 예제:

    #include <iostream>
    #include <vector>
    
    int main() {
        std::vector<int> numbers = {10, 20, 30};
        numbers.push_back(40); // 요소 추가
    
        for (int num : numbers) {
            std::cout << num << " "; // 출력: 10 20 30 40
        }
        return 0;
    }

1.1.2 리스트 (list)

  • 특징: 양방향 연결 리스트로, 삽입 및 삭제가 빠릅니다.

  • 예제:

    #include <iostream>
    #include <list>
    
    int main() {
        std::list<std::string> fruits = {"사과", "바나나"};
        fruits.push_back("오렌지"); // 마지막에 추가
    
        for (const auto& fruit : fruits) {
            std::cout << fruit << " "; // 출력: 사과 바나나 오렌지
        }
        return 0;
    }

1.1.3 셋 (set)

  • 특징: 중복되지 않는 요소들을 정렬된 상태로 유지합니다.

  • 예제:

    #include <iostream>
    #include <set>
    
    int main() {
        std::set<int> uniqueNumbers = {1, 2, 3};
        uniqueNumbers.insert(3); // 중복된 값은 무시됨
    
        for (int num : uniqueNumbers) {
            std::cout << num << " "; // 출력: 1 2 3
        }
        return 0;
    }

1.1.4 맵 (map)

  • 특징: 키와 값 쌍으로 데이터를 저장하며, 키를 통해 값을 검색할 수 있습니다.

  • 예제:

    #include <iostream>
    #include <map>
    
    int main() {
        std::map<std::string, int> ages = {{"Alice", 30}, {"Bob", 25}};
        ages["Charlie"] = 35; // 새로운 키-값 쌍 추가
    
        for (const auto& pair : ages) {
            std::cout << pair.first << ": " << pair.second << "\n";
        }
        return 0;
    }

1.1.5 큐 (queue)와 스택 (stack)

  • : FIFO(First In First Out) 원칙에 따라 작동합니다.

  • 스택: LIFO(Last In First Out) 원칙에 따라 작동합니다.

  • 예제:

    #include <iostream>
    #include <queue>
    #include <stack>
    
    int main() {
        std::queue<int> q;
        q.push(1);
        q.push(2);
        q.push(3);
    
        while (!q.empty()) {
            std::cout << q.front() << " "; // 출력: 1 2 3
            q.pop();
        }
    
        std::stack<int> s;
        s.push(1);
        s.push(2);
        s.push(3);
    
        while (!s.empty()) {
            std::cout << s.top() << " "; // 출력: 3 2 1
            s.pop();
        }
        return 0;
    }

2. 반복자: 컨테이너의 요소를 순회하는 도구

반복자는 컨테이너에 저장된 요소들을 순회하는 데 사용됩니다. 포인터와 유사하지만, 더 일반적이며 다양한 컨테이너에서 일관된 방식으로 사용할 수 있습니다. 반복자는 컨테이너의 시작과 끝을 나타내는 begin()end() 함수를 통해 얻을 수 있습니다.

2.1 반복자의 기본 사용 예시

#include <iostream>
#include <vector>

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

    // 벡터의 시작과 끝을 가리키는 반복자 생성
    std::vector<int>::iterator it;

    // 모든 요소 출력하기
    for (it = vec.begin(); it != vec.end(); ++it) {
        std::cout << *it << " "; // 각 요소 출력
    }
    return 0;
}

2.2 반복자의 종류

  1. 입력 반복자 (Input Iterator): 읽기 전용으로 데이터를 읽기만 할 수 있습니다.
  2. 출력 반복자 (Output Iterator): 쓰기 전용으로 데이터를 쓸 수 있습니다.
  3. 전진 반복자 (Forward Iterator): 한 방향으로만 이동 가능합니다.
  4. 양방향 반복자 (Bidirectional Iterator): 앞뒤로 모두 이동 가능합니다.
  5. 랜덤 접근 반복자 (Random Access Iterator): 임의의 위치로 직접 접근 가능합니다.

2.3 알고리즘과 함께 사용하는 방법

반복자는 STL 알고리즘과 함께 사용될 때 매우 강력합니다. 예를 들어, std::sort를 사용하여 벡터를 정렬할 수 있습니다.

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

int main() {
    std::vector<int> vec = {5, 3, 1, 4, 2};
    std::sort(vec.begin(), vec.end()); // 정렬

    for (const auto& num : vec) {
        std::cout << num << " "; // 출력: 1 2 3 4 5
    }
    return 0;
}

3. 알고리즘: 데이터를 처리하고 조작하는 도구

STL 알고리즘은 데이터 구조와 함께 사용되어 데이터를 처리하고 조작하는 데 매우 유용합니다. 주요 알고리즘으로는 정렬, 검색, 변환 등이 있습니다.

3.1 주요 알고리즘 예제

3.1.1 정렬 (Sorting)

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

int main() {
    std::vector<int> numbers = {5, 3, 8, 1, 2};
    std::sort(numbers.begin(), numbers.end()); // 오름차순 정렬

    for (int num : numbers) {
        std::cout << num << " "; // 출력: 1 2 3 5 8
    }
    return 0;
}

3.1.2 검색 (Search)

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

int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5};
    auto it = std::find(numbers.begin(), numbers.end(), 3); // 값 3 검색

    if (it != numbers.end()) {
        std::cout << "Found: " << *it << "\n"; // 출력: Found: 3
    } else {
        std::cout << "Not found\n";
    }
    return 0;
}

3.1.3 변환 (Transform)

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

int square(int x) { return x * x; }

int main() {
    std::vector<int> nums = {1, 2, 3};
    std::vector<int> squares(nums.size());

    std::transform(nums.begin(), nums.end(), squares.begin(), square);

    for (int s : squares) {
        std::cout << s << " "; // 출력: 1 4 9
    }
    return 0;
}

3.1.4 사용자 정의 비교 함수

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

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

int main() {
    std::vector<int> vec = {4, 1, 7};
    std::sort(vec.begin(), vec.end(), customCompare); // 내림차순 정렬

    for (int val : vec) {
        std::cout << val << " "; // 출력: 7 4 1
    }
    return 0;
}

4. 함수 객체: 알고리즘과의 통합을 위한 도구

함수 객체는 클래스로 정의된 객체로서, operator()를 오버로드하여 함수처럼 사용할 수 있습니다. 이는 STL 알고리즘과 함께 사용될 때 매우 유용합니다.

4.1 함수 객체의 기본 예제

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

class Compare {
public:
    bool operator()(int a, int b) const {
        return a > b; // 내림차순 정렬
    }
};

int main() {
    std::vector<int> vec = {4, 1, 3, 9, 2};
    std::sort(vec.begin(), vec.end(), Compare()); // 내림차순 정렬

    for (const auto& num : vec) {
        std::cout << num << " "; // 출력: 9 4 3 2 1
    }
    return 0;
}

4.2 함수 객체의 장점

  • 상태 유지: 일반적인 함수와 달리 상태(state)를 유지할 수 있어 복잡한 로직을 구현하기 용이합니다.
  • 커스터마이징 가능: 필요에 따라 여러 멤버 변수를 추가하여 다양한 동작을 수행하도록 할 수 있습니다.

4.2.1 예제

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

class Multiplier {
public:
    Multiplier(int factor) : factor(factor) {}

    int operator()(int value) const {
        return value * factor;
    }

private:
   int factor; 
};

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

   std::transform(nums.begin(), nums.end(), result.begin(), Multiplier(3));

   for (int val : result) {
       std::cout << val << " "; // 출력: 3 6 9
   }
   return 0;
}

결론

C++ 표준 라이브러리는 STL 컨테이너, 반복자, 알고리즘, 함수 객체 등을 통해 프로그래밍을 더 효율적이고 강력하게 만들어줍니다. 이러한 도구들을 잘 이해하고 활용하면, 코드의 가독성과 유지보수성이 크게 향상될 뿐만 아니라, 복잡한 문제를 더 쉽게 해결할 수 있습니다. 다양한 실습과 프로젝트를 통해 이들의 활용법을 익혀보시길 추천합니다!

728x90