C++ STL: 2장 - STL 컨테이너

2025. 1. 6. 16:17프로그래밍 언어/C++ STL

2.1 컨테이너의 이해

STL의 컨테이너(Container)는 데이터를 저장하고 관리하는 객체입니다. 각 컨테이너는 고유한 특성을 가지고 있어, 상황에 맞는 최적의 컨테이너를 선택하여 사용할 수 있습니다.

컨테이너는 크게 세 종류로 나뉩니다:

  • 순차 컨테이너: 데이터를 순서대로 저장
  • 연관 컨테이너: 키-값 쌍으로 데이터를 저장
  • 컨테이너 어댑터: 기존 컨테이너를 변형해 특별한 기능 제공

 

2.2 순차 컨테이너

순차 컨테이너는 데이터가 순차적으로 저장되며, 요소의 삽입과 삭제가 데이터의 순서에 영향을 미칩니다. 주요 순차 컨테이너는 다음과 같습니다:

 

2.2.1 vector (가변 크기 배열)

#include <iostream>
#include <vector>

int main() {
    std::vector<int> vec = {1, 2, 3};
    vec.push_back(4); // 끝에 요소 추가
    vec.pop_back();   // 끝에서 요소 제거

    for (const auto& elem : vec) {
        std::cout << elem << " ";
    }
    return 0;
}

특징:

  • 연속된 메모리 공간 사용
  • 빠른 임의 접근 (O(1))
  • 끝에서의 삽입/삭제는 빠르지만, 중간은 느림

 

2.2.2 list (이중 연결 리스트)

#include <iostream>
#include <list>

int main() {
    std::list<int> lst = {1, 2, 3};
    lst.push_front(0); // 앞에 요소 추가
    lst.push_back(4);  // 뒤에 요소 추가

    for (const auto& elem : lst) {
        std::cout << elem << " ";
    }
    return 0;
}

특징:

  • 어느 위치에서나 빠른 삽입/삭제 (O(1))
  • 임의 접근 불가능
  • 각 요소가 앞뒤 요소의 위치 정보를 가짐

 

2.2.3 deque (양방향 큐)

#include <iostream>
#include <deque>

int main() {
    std::deque<int> dq = {1, 2, 3};
    dq.push_front(0);
    dq.push_back(4);

    for (const auto& elem : dq) {
        std::cout << elem << " ";
    }
    return 0;
}

특징:

  • 양쪽 끝에서 빠른 삽입/삭제
  • 임의 접근 지원
  • vector와 list의 장점을 결합

 

2.2.4 array (고정 크기 배열)

#include <iostream>
#include <array>

int main() {
    std::array<int, 3> arr = {1, 2, 3};

    for (const auto& elem : arr) {
        std::cout << elem << " ";
    }
    return 0;
}

특징:

  • 크기가 고정되어 있음
  • 빠른 접근과 효율적인 메모리 사용
  • STL 컨테이너의 편리한 인터페이스 제공

 

2.3 연관 컨테이너

연관 컨테이너는 데이터를 키-값 쌍으로 저장하며, 자동으로 정렬되거나 해시 기반으로 저장됩니다. 주요 연관 컨테이너는 다음과 같습니다:

 

2.3.1 set과 multiset

#include <iostream>
#include <set>

int main() {
    std::set<int> s = {3, 1, 4};
    s.insert(2);

    for (const auto& elem : s) {
        std::cout << elem << " ";
    }
    return 0;
}

특징:

 

  • 자동 정렬
  • 키만 저장
  • 빠른 검색
  • set은 고유 / multiset은 중복 허용
  • 일반적으로 Red-Black Tree 기반 구현

 

2.3.2 map과 multimap

#include <iostream>
#include <map>

int main() {
    std::map<std::string, int> age_map = {
        {"Alice", 25}, {"Bob", 30}
    };
    age_map["Charlie"] = 20;

    for (const auto& [key, value] : age_map) {
        std::cout << key << ": " << value << "\n";
    }
    return 0;
}

특징:

  • 키-값 쌍 저장
  • 자동 정렬
  • map은 키 고유 / multimap은 키 중복 허용
  • 일반적으로 Red-Black Tree 기반 구현

 

2.3.3 unordered_set과 unordered_map

#include <iostream>
#include <unordered_set>
#include <unordered_map>

int main() {
    std::unordered_set<int> uset = {1, 2, 3};
    uset.insert(4);

    std::unordered_map<std::string, int> umap = {
        {"Alice", 25}, {"Bob", 30}
    };
    umap["Charlie"] = 20;

    // 출력 생략
    return 0;
}

특징:

  • 해시 테이블 기반
  • 매우 빠른 검색/삽입/삭제 (평균 O(1) /  최악 O(n) )
  • 정렬되지 않음

 

2.4 컨테이너 어댑터

컨테이너 어댑터는 기본 컨테이너의 인터페이스를 변경하여 스택, 큐, 우선순위 큐와 같은 특수 목적의 컨테이너를 제공합니다.

 

2.4.1 stack (LIFO)

#include <iostream>
#include <stack>

int main() {
    std::stack<int> stk;
    stk.push(1);
    stk.push(2);

    while (!stk.empty()) {
        std::cout << stk.top() << " ";
        stk.pop();
    }
    return 0;
}

 

2.4.2 queue (FIFO)

#include <iostream>
#include <queue>

int main() {
    std::queue<int> q;
    q.push(1);
    q.push(2);

    while (!q.empty()) {
        std::cout << q.front() << " ";
        q.pop();
    }
    return 0;
}

 

2.4.3 priority_queue (우선순위 큐)

#include <iostream>
#include <queue>

int main() {
    std::priority_queue<int> pq;
    pq.push(10);
    pq.push(5);
    pq.push(20);

    while (!pq.empty()) {
        std::cout << pq.top() << " ";
        pq.pop();
    }
    return 0;
}

 

마무리

STL 컨테이너는 다양한 데이터 구조를 효율적으로 사용할 수 있게 해줍니다. 각 컨테이너의 특성을 이해하고 상황에 맞게 선택하면 프로그램의 성능을 크게 향상시킬 수 있습니다. 다음 장에서는 이러한 컨테이너들을 효과적으로 다루는 데 사용되는 이터레이터에 대해 알아보겠습니다.