template<class T1, class T2>
struct pair {
T1 first;
T2 second;
};
pair
는 두 개의 타입을 하나로 묶은 구조체이다. <utility>
에서 다음과 같은 구조로 정의되어 있다. 대부분의 컨테이너는 utility를 포함하고 있기 때문에 컨테이너 헤더를 포함했다면, <utility>
헤더를 직접 포함하지 않고도 사용할 수 있다.
직접 구조체를 만드는 것에 비해 pair을 사용하는 이점은 복사, 이동과 같은 다양한 생성 연산이 구현되어 있다는 것과 비교/대소 연산이 정의되어 있어 이와 관련된 코드를 다시 작성할 필요가 없다는 것이다.
사용법
생성
- 기본 생성자
- first와 second를 입력 받는 생성자 (이동 연산 포함)
- list_initializer
- 복사와 이동 생성자
- make_pair() 함수 이용
#include<utility>
#include<string>
using namespace std;
int main() {
// 1. 기본 생성자
pair<int, int> p1; // 0 0
pair<int, float> p1_1; // 0 0.000..
pair<double, string> p1_2; // 0.000.. ""
// 2. first와 second를 입력 받는다.
pair<int, int> p2(1,2); // 1 2
// 3. list_initializer
pair<int, int> p3{ 2,3 }; // 2 3
pair<int, int> p3_2 = { 2,3 };
pair<int, int> p3_3({ 2,3 });
// 4. 복사, 이동 생성자 및 대입 연산자
pair<int, int> p4(p3); // 2 3
pair<int, int> p4_2(pair<int,int>(1,1)); // 1 1
pair<int, int> p4_3 = p4;
// make_pair
auto p5 = make_pair<int, int>(1, 1);
auto p6 = make_pair(1, 1);
}
접근
각 요소에 접근하는 두 가지 방법이 있다. 첫 번째는 .first
, .second
로 멤버에 직접 접근하는 방법이고, 다른 하나는 get<n>(pair)
를 사용하는 방법이다. 마지막은 구조적 바인딩을 이용하는 것이다.
// 1. 멤버에 직접 접근
pair<int, string> p{ 1, "" };
p.first = 5;
p.second = "뉴진스";
cout << p.first << ", " << p.second << endl;
// 2. get<n>(pair) 사용
get<0>(p) = 11;
cout << get<0>(p) << ", " << get<1>(p) << endl;
// 3. structured binding
auto& [i, str] = p;
str = "스진뉴";
cout << i << ", " << str << endl;
5, 뉴진스
11, 뉴진스
11, 스진뉴
비교
pair의 비교 연산은 첫 번쨰를 기준으로 이루어진다. 만약 first가 같다면 second 비교를 통해 비교 연산을 수행한다. 두 요소가 모두 같다면 두 pair는 같다. 당연히 first와 second의 타입인 T1과 T2의 연산자가 정의되어 있어야 한다.
pair<int, int> p1{ 0,1 };
pair<int, int> p2{ 1,0 };
pair<int, int> p3{ 0,2 };
pair<int, int> p4{ 0,1 };
// <= 와 >=도 가능
cout << (p1 > p2) << endl; // 0
cout << (p1 > p3) << endl; // 0
cout << (p1 == p4) << endl; // 1
cout << (p1 != p2) << endl; // 1
교환
swap()
함수를 통해서 두 pair을 쉽게 교환할 수 있다.
pair<int, int> p1 = { 1,1 };
pair<int, int> p2 = { 2,2 };
cout << "최초 값" << endl;
cout << p1.first << ", " << p1.second << endl;
cout << p2.first << ", " << p2.second << endl;
// swap method
p1.swap(p2);
cout << "교환" << endl;
cout << p1.first << ", " << p1.second << endl;
cout << p2.first << ", " << p2.second << endl;
// swap function
swap(p1, p2);
cout << "재교환" << endl;
cout << p1.first << ", " << p1.second << endl;
cout << p2.first << ", " << p2.second << endl;
최초 값
1, 1
2, 2
교환
2, 2
1, 1
재교환
1, 1
2, 2
사용 예시
컨테이너의 타입으로 사용
다음은 vector 컨테이너의 타입으로 pair<int,int>
를 사용하는 예시이다. 코드는 백준 11000번 강의실 배정 문제의 풀이 코드이다. 정확한 내용은 강의가 시작 시간과 끝 시간으로 주어졌을 때, 이를 먼저 끝나는 강의 순으로 정렬한 다음, 겹치지 않는 다음 강의를 선택해 가능한 최대의 강의 수를 구하는 코드이다. 이런식으로 컨테이너 요소의 타입으로 사용할 수 있는 예를 보이기 위함이기 때문에 코드를 이해하지 못하더라도 문제는 없다.
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int main() {
int N; // 회의의 개수
cin >> N; // 회의의 수를 입력 받는다.
// 회의 수만큼 컨테이너의 공간을 확보한다.
vector<pair<int,int>> meeting(N);
for(int i=0; i<N; i++) { // N번 반복
int s; // 회의 시작시간
int e; // 회의 종료 시간
cin >> s >> e; // 두 시간을 입력 받는다.
// pair{e,s}를 컨테이너에 삽입한다.
meeting[i] = make_pair(e,s);
}
// 먼저 끝나는 순으로 컨테이너를 정렬한다.
// meeting의 first인 e가 오름차순으로 정렬
// e가 같은 경우에 한해서 second인 s 순으로 오름차순 정렬
sort(meeting.begin(), meeting.end());
int ans=0; // 정답
int t=0; // 현재 시간
// 현재 회의가 끝난 다음 고를 수 있느 회의를 찾는다.
for(auto& [e,s] : meeting) {
if (s >= t) {
ans++;
t = e;
}
}
cout << ans;
}
map 컨테이너에서
map 컨테이너는 key와 value 두 가지 값을 묶어서 저장하는 컨테이너이다. 이터레이터로 어떤 요소에 접근할 때, pair<&key, &value>
형태로 레퍼런스를 반환한다. 역시 pair를 반환하는 컨테이너가 있음을 보여주기 위함이었기 때문에 map에 대해 잘 이해가 안가더라도 문제 없다.
#include<map>
#include<iostream>
using namespace std;
int main() {
map<int, string> m{
{1, "브로콜리너마저"},
{2, "쏜애플"},
{3, "델리스파이스"}
};
auto iter = m.begin();
pair<int, string> p = (*iter);
cout << get<0>(p) << ", " << get<1>(p) << endl;
}
1, 브로콜리너마저