2013-06-13 2 views
5

회원 x, y, z 및 w가있는 구조체가 있습니다. 어떻게 효율적으로 정렬합니까 x에 의해 다음 y에 의해 z에 의해 그리고 마지막으로 승에 의해 C + +에서?C++에서 4 중 구조체를 효율적으로 정렬하려면 어떻게해야합니까?

+1

: 및 기타 시설의 건설을 필요로하지 않습니다 전진. 예 : 버킷 정렬 ('w'에서'x'까지)의 네 패스는 비교 정렬 기반 메소드보다 효율적일 수 있습니다. – jogojapan

+2

'튜플 (tuple) '비교를 사용하면 구현시 플랫폼 순서에 따른 최적화를 순서와 방식대로 사용할 수 있다는 장점이 있습니다. 데이터 유형이나 데이터의 특성이 허용하는 경우 물론 그보다 훨씬 더 나은 작업을 수행 할 수 있습니다. SIMD 명령어를 사용하여 하나의 연산에서 4 가지를 모두 비교할 수 있습니다. – yzt

답변

9

사전 식 순서를 구현하려면 가장 간단한 방법은 std::tie을 사용하여보다 작거나 큰 비교 연산자 또는 펑터를 구현 한 다음 구조체 컬렉션에 std::sort을 사용하는 것입니다. Foo의 자연 순서가없는 경우

struct Foo 
{ 
    T x, y, z, w; 
}; 

....  
#include <tuple> // for std::tie 

bool operator<(const Foo& lhs, const Foo& rhs) 
{ 
    // assumes there is a bool operator< for T 
    return std::tie(lhs.x, lhs.y, lhs.z, lhs.w) < std::tie(rhs.x, rhs.y, rhs.z, rhs.w); 
} 

.... 

#include <algorithm> // for std::sort 

std::vector<Foo> v = ....; 
std::sort(v.begin(), v.end()); 

, 대신 비교 연산자를 구현하는 비교 펑터를 정의하는 것이 더있을 수 있습니다. 그런 종류의 이러한 전달할 수 있습니다 : 당신이 C++ 11 tuple 지원이없는 경우

bool cmp_1(const Foo& lhs, const Foo& rhs) 
{ 
    return std::tie(lhs.x, lhs.y, lhs.z, lhs.w) < std::tie(rhs.x, rhs.y, rhs.z, rhs.w); 
} 

std::sort(v.begin(), v.end(), cmp_1); 

, 당신이 사용 std::tr1::tie (사용 헤더 <tr1/tuple>) 또는 boost.tuple library에서 boost::tie를 사용하여 구현할 수 있습니다.

+0

가장 간단 합니다만, 단순한 비교 순서만큼 효율적입니까? – Spook

+2

@ Spook 그렇지 않다면 놀랄 것입니다. – juanchopanza

+0

OP는 효율적이고 쉬운 방법을 요구하지 않았습니다 :) – Spook

6

std::tie을 사용하여 구조체를 std::tuple으로 바꿀 수 있으며 사전 식 비교 std::tuple::operator<을 사용할 수 있습니다. 여기 std::sort

#include <algorithm> 
#include <tuple> 
#include <vector> 

struct S 
{ 
    // x, y, z, w can be 4 different types! 
    int x, y, z, w; 
}; 

std::vector<S> v; 

std::sort(std::begin(v), std::end(v), [](S const& L, S const& R) { 
    return std::tie(L.x, L.y, L.z, L.w) < std::tie(R.x, R.y, R.z, R.w); 
}); 

이 예 즉석 비교 연산자 std:sort 공급 람다를 사용하는 예이다. 사전 편집 비교를 항상 사용하려는 경우 std::sort으로 자동 선택되거나 std::setstd::map과 같은 정렬 된 연관 컨테이너로 비회원 bool operator<(S const&, S const&)을 작성할 수 있습니다. online reference에서 효율 대하여

:

모든 비교 연산자 단락; 비교 결과를 결정하는 데 필요한 것 이상의 튜플 에 액세스하지 않습니다.

C++ 11 환경을 사용하는 경우 여기에 제시된 직접 작성 솔루션보다 std::tie을 선호합니다. 그들은 오류가 발생하기 쉽고 읽기 쉽지 않습니다.

2

비교 연산자를 굴리면 객체를 std::map으로 자유롭게 던지거나 std::sort을 호출 할 수 있습니다. 이 구현은 단순하도록 설계되었으므로 필요한 경우 쉽게 확인하고 수정할 수 있습니다. operator<을 x, y, z 및 w와 비교하는 것만으로 변수가 이미 비교 가능하지 않은 경우 구현해야 할 연산자 수를 최소화합니다 (예 : int, double, std가 아닌 자신의 구조체 인 경우). 문자열 등).

bool operator<(const Q& lhs, const Q& rhs) 
{ 
    if (lhs.x < rhs.x) return true; 
    if (rhs.x < lhs.x) return false; 
    if (lhs.y < rhs.y) return true; 
    if (rhs.y < lhs.y) return false; 
    if (lhs.z < rhs.z) return true; 
    if (rhs.z < lhs.z) return false; 
    if (lhs.w < rhs.w) return true; 
    return false; 
} 

때때로 유형 ==, <=, <의 구현을 지원하기 위해보다 작음 방법으로 모두 동일하거나보다 큰 나타낼 -1, 0 또는 1을 반환 비교 함수를 정의하고, != , >=> 일 때와 마찬가지로 <을 수행하면 != 또는 >이 많은 작업을 반복합니다 (마지막 문자 만 다른 긴 텍스트 문자열 비교를 고려하십시오).x가, y는, Z와 w는 유형이 될 일이 더 높은 성능의 기능을 비교하는 경우, 당신은 아마도 전반적인 성능을 향상시킬 수

bool operator<(const Q& lhs, const Q& rhs) 
{ 
    int c; 
    return (c = lhs.x.compare(rhs.x) ? c : 
      (c = lhs.y.compare(rhs.y) ? c : 
      (c = lhs.z.compare(rhs.z) ? c : 
      lhs.w < rhs.w; 
} 
+0

juanchopanza가 제안한 것보다 나은가? – user2381422

+0

덜 우아하지만 빠릅니다. – Spook

+0

@Spook 그 청구를 뒷받침 할 전화 번호가 있습니까? – juanchopanza

2

이 솔루션을 당 대부분 4 개 비교에서 요소-비교 정렬 특히 _efficient_가 (당신이 요청으로) 정렬 된 값의 범위에 따라 얼마나 많은 것은 그들에 대해 알려진하는 방법을 결정하는 모든 종류의와 마찬가지로

// using function as comp 
std::sort (quadrupleVec.begin(), quadrupleVec.end(), [](const Quadruple& a, const Quadruple& b) 
{ 
    if (a.x != b.x) 
     return a.x < b.x; 

    if (a.y != b.y) 
     return a.y < b.y; 

    if (a.z != b.z) 
     return a.z < b.z; 

    return a.w < b.w; 
}); 
+0

다른 사람들이 이미 제안한 것과 귀하의 접근 방식을 비교해 볼 수 있습니까? – user2381422

+0

좋은 하나! 비교가 훨씬 적습니다. +1 :) – Spook

+0

7 개의 비교가 모두 평가되는 코드 경로가 없습니다. – Enigma