본문 바로가기

Programming/C & C++

[C++ STL] set, map 정렬 기준 바꾸는 방법

C++ STL에서 제공하는 set, map, multiset, multimap 등의 컨테이너는 자동으로 데이터를 정렬된 상태로 유지시켜 줍니다. 그래서 이러한 컨테이너에 데이터를 넣고 그대로 출력하기만 하면 오름차순으로 정렬된 데이터를 얻을 수 있죠. 하지만 가끔은 내림차순 정렬이 필요하거나 내가 원하는 방식대로 정렬되어야 하는 경우도 생깁니다. 이럴 때 어떻게 할 수 있을까요? set 컨테이너로 예를 들어 설명해 보겠습니다.


set의 템플릿(template)을 살펴보면 다음과 같이 되어 있습니다.

template <class _Kty, class _Pr = less<_Kty>, class _Alloc = allocator<_Kty>>

_Kty 부분은 흔히 사용하는 키 타입을 설정하는 부분입니다. 우리가 봐야 할 부분은 바로 _Pr 부분입니다. 기본 값으로 less가 설정된 모습을 볼 수 있는데 이 less는 아래와 같이 정의되어 있습니다.

template <class _Ty = void>
struct less {
    _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef _Ty first_argument_type;
    _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef _Ty second_argument_type;
    _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef bool result_type;

    constexpr bool operator()(const _Ty& _Left, const _Ty& _Right) const {
        return _Left < _Right;
    }
};

less는 구조체 형태로 정의되어 있고 내부에는 operator() 형태로 연산자 오버로딩(operator overloading)이 사용되고 있습니다. 또한 그 내용을 보면 _Left_Right의 크기를 비교해서 결과를 반환하고 있죠. 바로 이 less가 기본적으로 설정되어 있었기 때문에 오름차순으로 정렬되었던 것입니다.

 

때문에 정렬 기준을 바꾸기 위해선 저 _Pr 부분에 다른 코드를 넣어주면 됩니다. 단순 비교만 하는 경우 STL 자체에서 지원하는 greater, less, greater_equal, less_equal 등이 있으므로 골라서 사용하시면 됩니다. 만약 내림차순으로 정렬 기준을 바꾸고 싶은 경우 greater를 이용해 코딩하시면 됩니다.

#include <iostream>
#include <set>

using namespace std;

int main()
{
	set<string, greater<string>> s;
	s.insert("apple");
	s.insert("banana");
	s.insert("melon");

	for (const auto& str : s) {
		cout << str << endl;
	}

	return 0;
}

내림차순 정렬에 대한 실행 결과

정렬 기준을 내가 원하는 대로 직접 만들어야 하는 경우도 있습니다. 그럴 땐 직접 비교용 구조체를 만들어서 사용하시면 됩니다. 예를 들어 오름차순 정렬이지만 길이가 짧은 문자열을 우선해서 정렬해야 하는 경우를 생각해 보겠습니다. 그럴 경우 아래와 같이 코딩하시면 됩니다.

#include <iostream>
#include <set>

using namespace std;

// 직접 추가한 비교용 구조체
struct myOrder
{
	bool operator() (const string& left, const string& right) const
	{
		if (left.size() == right.size()) {
			return left < right;
		}
		else {
			return left.size() < right.size();
		}
	}
};

int main()
{
	set<string, myOrder> s;
	s.insert("apple");
	s.insert("banana");
	s.insert("melon");

	for (const auto& str : s) {
		cout << str << endl;
	}

	return 0;
}

오름차순 정렬이지만 길이가 짧은 문자열을 우선한 실행 결과

지금까지 set 컨테이너로 예를 들어 설명했지만 다른 컨테이너 역시 같은 방법으로 적용시켜서 사용하시면 됩니다.