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 반복자의 종류
- 입력 반복자 (Input Iterator): 읽기 전용으로 데이터를 읽기만 할 수 있습니다.
- 출력 반복자 (Output Iterator): 쓰기 전용으로 데이터를 쓸 수 있습니다.
- 전진 반복자 (Forward Iterator): 한 방향으로만 이동 가능합니다.
- 양방향 반복자 (Bidirectional Iterator): 앞뒤로 모두 이동 가능합니다.
- 랜덤 접근 반복자 (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 컨테이너, 반복자, 알고리즘, 함수 객체 등을 통해 프로그래밍을 더 효율적이고 강력하게 만들어줍니다. 이러한 도구들을 잘 이해하고 활용하면, 코드의 가독성과 유지보수성이 크게 향상될 뿐만 아니라, 복잡한 문제를 더 쉽게 해결할 수 있습니다. 다양한 실습과 프로젝트를 통해 이들의 활용법을 익혀보시길 추천합니다!
'프로그래밍 > C++' 카테고리의 다른 글
C++ 메모리 관리: 동적 메모리 할당과 스마트 포인터를 활용한 효율적인 자원 관리 (0) | 2025.02.02 |
---|---|
C++ 고급 기능: 템플릿, 예외 처리, 네임스페이스, 람다 표현식 (0) | 2025.02.02 |
객체 지향 프로그래밍(OOP)의 핵심 개념: 클래스, 객체, 생성자, 소멸자, 상속, 다형성 (0) | 2025.02.02 |
C++ 프로그래밍 기초: 데이터 타입, 변수, 연산자, 제어문, 함수 (0) | 2025.02.02 |
최신 C++ 기능으로 더 효율적이고 안전한 코드 작성하기 (1) | 2025.02.01 |