Posted Updated

문제 소개

Image

https://www.acmicpc.net/problem/1427

숫자의 각 자릿수를 내림차순으로 정렬 하는 문제를 풀다가 greater<T>()에 대해 자세히 알아보게 되었다.

위 문제는 예를 들어 입력값이 2143이라면, 각 자릿수 '2', '1', '4', '3'을 내림차순으로 정렬해 4321로 출력하는 문제다.
문자열로 변환한 뒤 sort() 함수의 3번째 인자로 greater<char>()를 함께 넘기면 된다는 것을 알게 되었지만, 왜 그렇게 동작하는지 정확히 이해하고 싶었다.

이 글에서는 STL의 greater<T>()가 어떻게 동작하는지 , 그리고 sort() 함수에서 어떻게 내림차순을 만들 수 있는지 정리해 본다.

[C++]

#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

int main() {
    string N;
    cin >> N;

    sort(N.begin(), N.end(), greater<char>());

    cout << N;

    return 0;
}

수 N을 string으로 받아 각 문자(char)를 정렬할 계획을 짰다.
이때 내림차순이라는 기준으로 사용된 것이 greater<char>()였다.

greater<T>()란?

C++ STL의 greater<T>함수 객체(Function Object) 로, 두 값 a, b를 받아 a > b 를 반환하는 구조체이다.

template <class T>
struct greater {
    bool operator()(const T& a, const T& b) const {
        return a > b;
    }
};

즉, 정렬 시 a > b이면 a를 앞에 배치 -> 내림차순 정렬이 된다.

함수 객체(Function Object)란?

() 연산자(함수 호출 연산자)를 오버로드한 클래스의 인스턴스로, 함수처럼 동작하는 객체이다.
객체인데 함수처럼 사용할 수 있는 것으로 보면 된다.

예제. 함수 객체 직접 만들어 보기

#include <iostream>
using namespace std;

struct Add {
    int operator()(int a, int b) const {
        return a + b;
    }
};

int main() {
    Add add;     // 함수 객체 생성

    cout << add(3, 5);     // 함수처럼 호출 가능

    return 0;
}

🔽 출력 :

8

Add() 연산자를 오버로드했기 때문에 함수처럼 add(3, 5)로 사용할 수 있다.
이것이 함수 객체이다. 함수와는 달리 멤버 변수를 가져 상태를 저장할 수 있다는 장점이 있다.

대표적인 함수 객체로는 equal_to<T>() 같은 것이 있다.

sort() 함수의 정렬 기준 바꾸기

기본적인 std::sort()는 오름차순 정렬을 수행한다.

sort(v.begin(), v.end());

우리가 자주 쓰는 sort 함수인데, 이 sort 함수에는 3번째 인자가 생략되어 있다.
sort() 함수의 3번째 인자에는 비교자가 들어가는데, 3번째 인자를 생략하면 default로 less<T>()가 들어간다.

std::sort의 비교 방식

std::sort(first, last, comp);

여기서 comp은 비교 함수 객체이고 함수처럼 호출할 수 있다.

comp(a, b)는 이렇게 해석된다.

a는 b보다 앞에 와야 하는가? 참이면 a는 b보다 앞에 와야 한다.

즉, comp(a, b) == true이면 a는 b보다 앞에 와야 한다는 뜻이다.

less<T>()란?

less<T>()는 C++ STL에서 제공하는 함수 객체(Function Object) 중 하나로, 비교 대상 a, b에 대해 a < b 를 반환하는 객체이다.
즉, less<T>()작은 값이 앞에 오도록 하는 오름차순 정렬 을 위한 기본 비교자이다.

template <class T>
struct less {
    bool operator()(const T& a, const T& b) const {
        return a < b;
    }
};

operator()를 정의한 함수 객체이기 때문에 함수처럼 사용할 수 있는 객체이다.

예제 코드로 이해하기

비교 기준을 바꾸고 싶을 때는 함수 객체를 세 번째 인자로 넘긴다.

예제 1. 오름차순 정렬 (기본)

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
    vector<int> v = {3, 1, 4, 1, 5};

    sort(v.begin(), v.end());     // 기본 정렬 : less<int>()

    for (int i : v)
        cout << i << " ";
}

🔽 출력 :

1 1 3 4 5


예제 2. 내림차순 정렬 (greater<T>())

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
    vector<int> v = {3, 1, 4, 1, 5};

    sort(v.begin(), v.end(), greater<int>());

    for (int i : v)
        cout << i << " ";
}

🔽 출력 :

5 4 3 1 1


요약

이름 의미 비교 방식 정렬 결과
less<T>() (기본) 오름차순 a < b 작은 값이 앞에 옴
greater<T>() 내림차순 a > b 큰 값이 앞에 옴

마무리

greater<T>()는 정렬 기준을 내림차순으로 바꾸고 싶을 때 가장 직관적으로 사용할 수 있는 도구다.
함수 객체의 개념을 이해하면 STL의 다양한 알고리즘 함수들을 더욱 유연하게 활용할 수 있다.

Leave a comment