문제
연산자 오버로딩 이론까지 모두 배웠다.
이제는 이들을 응용하여, 가장 중요한 기법 중 하나인 구조체(struct) 정렬을 익혀보자!
학생들의 정보가 이름(string)과 나이(int) 로 주어져 있다.
10명의 정보를 입력 받아, 1순위 : 나이 , 2순위 : 이름 을 기준으로 정렬하고 싶은 상황이다.
우선, 틀린 코드부터 보자.
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
struct Student{
string name; // 이름
int age; // 나이
};
int main(){
int i;
Student arr[10];
// 입력
for(i = 0; i < 10; i++) {
cin >> arr[i].name >> arr[i].age;
}
// 정렬
sort(arr, arr + 10);
}위 코드를 컴파일하면, 오류가 발생한다. 왜 그럴까?
그냥 무작정 sort 함수를 돌리면, 컴퓨터 입장에서는 name, age 중 어떤 것을 기준으로 정렬해야 될 지 모르기 때문이다.
여러 변수를 관리하는 구조체를 정렬할 때는, 반드시 정렬 기준을 명시해야 한다.
방법은 크게 2가지다.
방법 1 : comp 함수를 이용한 정렬 기준 설정
이 방법은 STL Sort 함수에 정렬 기준을 넣는 것을 응용한다.
이 때 배운 방법대로, 두 개의 Student 구조체를 받아오는 bool comp 함수를 만들어, sort 함수 인자에 추가하면 된다.
bool comp(Student Left, Student Right){
// 1순위 정렬 기준 : 나이
// 나이가 다르다면, 무조건 나이를 기준으로 비교한다.
if(Left.age != Right.age) return Left.age < Right.age;
// 2순위 정렬 기준 : 이름
// 나이가 같았다면, 이름을 기준으로 비교한다.
return Left.name < Right.name;
}
sort( arr , arr + 10 , comp ); // comp 함수를 마지막에 추가하여 정렬 기준을 설정방법 2 : 연산자 오버로딩을 이용한 정렬 기준 설정
이 방법은 앞서 배운 연산자 오버로딩으로 정렬한다.
별도의 comp 함수를 만드는 것이 아니라, 구조체 안에 < 연산자 를 넣어서 비교하는 것이다.
이것을 이해하는 것도 앞선 논리와 비슷하다.
배열에서 오른쪽으로 갈수록 나이가 많아지길 원하니, age < Right.age 가 되는 것이다.
struct Student{
string name;
int age;
bool operator<(const Student &Right) const{
if(age != Right.age) return age < Right.age;
return name < Right.name;
}
}
// Student 구조체 안에 이미 정렬 기준이 들어가 있기에, sort 함수에 인자를 추가할 필요는 없다.
sort( arr , arr + 10 ); 응용 : 서로 다른 정렬 기준으로 두 번 정렬하고 싶다면?
방금 우리는 "1순위 : 나이 , 2순위 : 이름" 으로 정렬했었다.
이후에, 이를 바꾸어 "1순위 : 이름 , 2순위 : 나이" 로 한 번 더 정렬하고 싶다면 어떻게 하면 될까?
// 정렬 기준 1 : 나이, 이름 순서
bool comp1 ( Student Left , Student Right ){
if(Left.age != Right.age) return Left.age < Right.age;
return Left.name < Right.name;
}
// 정렬 기준 2 : 이름, 나이 순서
bool comp2 ( Student Left , Student Right ){
if(Left.name != Right.name) return Left.name < Right.name;
return Left.age < Right.age;
}
sort( arr , arr + 10 , comp1 ); // 정렬 기준 1 로 정렬
sort ( arr , arr + 10 , comp2 ); // 정렬 기준 2 로 정렬위처럼, comp 함수를 2개 만들어서 하면 된다.
comp1 을 넣으면 comp1 대로, comp2 를 넣으면 comp2 대로 정렬된다.
아니면, 아래 코드처럼 해도 된다.
struct Student{
string name;
int age;
bool operator<(const Student &Right) const{
if(age != Right.age) return age < Right.age;
return name < Right.name;
}
}
bool comp( Student Left , Student Right ){
if(Left.name != Right.name) return Left.name < Right.name;
return Left.age < Right.age;
}
sort( arr , arr + 10 ); // sort 뒤에 comp 가 없음 : 구조체에 들어있는 정렬 기준대로 정렬됨
sort( arr , arr + 10 , comp ); // sort 뒤에 comp 가 있음 : comp 의 정렬 기준대로 정렬됨정렬 기준 하나는 구조체 안에 넣고 ( bool operator < ),
나머지 하나는 구조체 밖에 구현한 것이다. ( bool comp 함수 )
sort(arr, arr+10) 처럼 뒤에 comp 가 없을 때는, 우리가 bool operator < 로 구조체 안에 넣어준 정렬 기준대로 sort 된다.
sort(arr, arr+10, comp) 처럼 뒤에 comp 가 있을 때는, 구조체 밖 comp 함수의 정렬 기준대로 sort 된다.
( 구조체 안에 있는 bool operator < 는 무시된다. )
이제 이를 이용한 문제를 풀어보자.
나이(int), 키(double) 로 구성된 사람들의 정보가 N 개 입력된다.
1순위 : 나이의 내림차순, 2순위 : 키의 내림차순을 기준으로 정렬하여 출력하고,
이후에 1순위 : 키의 오름차순, 2순위 : 나이의 오름차순을 기준으로 정렬하여 출력하자.
입력
첫 줄에 N 이 입력된다. ( 1 ≤ N ≤ 100,000 )
이후 N 줄에 걸쳐 나이와 키가 입력된다. ( 나이와 키 모두 0 이상 1만 이하 )
모든 키는 소수점 아래 한 자리만 입력된다.
출력
1순위 : 나이의 내림차순, 2순위 : 키의 내림차순을 기준으로 정렬하여 출력한다.
이후 줄 바꿈을 한 번 더 하고,
1순위 : 키의 오름차순, 2순위 : 나이의 오름차순을 기준으로 정렬하여 출력한다.
( 키를 출력할 때는, 무조건 "소수점 둘째 자리에서 반올림"하여, 소수점 첫째 자리까지 출력한다. )
( 키가 100 으로 정수여도, 무조건 100.0 으로 출력해야 한다. )
예제
7
1 2.4
9 9.9
9 5.5
9 8.0
1 5.5
1 8.0
3 5.5
9 9.9
9 8.0
9 5.5
3 5.5
1 8.0
1 5.5
1 2.4
1 2.4
1 5.5
3 5.5
9 5.5
1 8.0
9 8.0
9 9.9