template<class T1, class T2>
struct pair {
    T1 first;
    T2 second;
};

   pair는 두 개의 타입을 하나로 묶은 구조체이다. <utility>에서 다음과 같은 구조로 정의되어 있다. 대부분의 컨테이너는 utility를 포함하고 있기 때문에 컨테이너 헤더를 포함했다면, <utility> 헤더를 직접 포함하지 않고도 사용할 수 있다.

   직접 구조체를 만드는 것에 비해 pair을 사용하는 이점은 복사, 이동과 같은 다양한 생성 연산이 구현되어 있다는 것과 비교/대소 연산이 정의되어 있어 이와 관련된 코드를 다시 작성할 필요가 없다는 것이다.


 

사용법

생성

  1. 기본 생성자
  2. first와 second를 입력 받는 생성자 (이동 연산 포함)
  3. list_initializer
  4. 복사와 이동 생성자
  5. 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, 브로콜리너마저