두 범위 내에서 내림차순으로 벡터 정렬


14

정수 벡터가 있다고 가정 해보십시오.

std::vector<int> indices;
for (int i=0; i<15; i++) indices.push_back(i);

그런 다음 내림차순으로 정렬합니다.

sort(indices.begin(), indices.end(), [](int first, int second) -> bool{return indices[first] > indices[second];})
for (int i=0; i<15; i++) printf("%i\n", indices[i]);

이것은 다음을 생성합니다.

14
13
12
11
10
9
8
7
6
5
4
3
2
1
0

이제 숫자 3, 4, 5 및 6을 끝으로 옮기고 내림차순을 유지하고 싶습니다 (바람직하게 sort는 두 번째 로 사용하지 않아도 됨 ). 즉, 여기 내가 원하는 것입니다 :

14
13
12
11
10
9
8
7
2
1
0
6
5
4
3

그것을 std::sort달성하기 위해 의 비교 함수를 어떻게 수정해야 합니까?


4
return indices[first] > indices[second]당신은 의미하지 return first < second;않습니까?
acraig5075

2
간단한 내림차순 정렬 을 위해 람다 대신 std::greater에서를 <functional>사용할 수 있습니다. 귀하의 질문에 관해서는, 귀하가 원하는 방식으로 가치를 비교하는 가장 자세한 비교기를 작성하는 것이 가장 쉬운 방법 일 수 있습니다.
sweenish

4
@ acraig5075는 내림차순으로이어야합니다 return first > second.
ks1322

1
@ acraig5075 뭔가 빠진 것 같은 느낌이 들거나 사람들은 오름차순내림차순 의 차이점을 모르 십니까?
sweenish

3
아마 당신은 std :: rotate ?
슈퍼

답변:


8

귀하의 비교 기능을 사용으로 얻을 수있는 값부터 잘못 firstsecond의 요소입니다 std::vector. 따라서 인덱스로 사용할 필요가 없습니다. 따라서 변경해야합니다

return indices[first] > indices[second];

return first > second;

자, 당신이 해결하려는 문제에 관해서는 ...

다른 요소와 비교하지 않고 3, 4, 5 및 6을 그대로두고 서로 비교할 수 있습니다.

std::sort(
    indices.begin(), indices.end(),
    [](int first, int second) -> bool {
        bool first_special = first >= 3 && first <= 6;
        bool second_special = second >= 3 && second <= 6;
        if (first_special != second_special)
            return second_special;
        else
            return first > second;
    }
);

데모


@NutCracker 네, 우선 최고의 기준을 갖는 것이 더 좋다는 데 동의합니다.
힙 오버플로

5

로부터 기능 표준 알고리즘 라이브러리iota, sort, find, rotate그리고 copy여러분의 인생을 더 쉽게 만드는 것입니다. 귀하의 예는 다음과 같습니다.

#include <iostream>
#include <vector>
#include <numeric>
#include <algorithm>
#include <iterator>


int main()
{
  std::vector<int> indices(15);
  std::iota(indices.begin(), indices.end(), 0);
  std::sort(indices.begin(), indices.end(), std::greater<>());

  auto a = std::find(indices.begin(), indices.end(), 6);
  auto b = std::find(indices.begin(), indices.end(), 3);
  std::rotate(a, b + 1, indices.end());

  std::copy(indices.begin(), indices.end(), std::ostream_iterator<int>(std::cout, "\n"));
  return 0;
}

산출:

14
13
12
11
10
9
8
7
2
1
0
6
5
4
3


의견에 @TedLyngmo는 다음과 같이 개선 할 수 있음을 지적합니다.

auto a = std::lower_bound(indices.begin(), indices.end(), 6, std::greater<int>{});
auto b = a + 4;

auto b = a + 4;잘못되었습니다 (이전 스 니펫과 일관성을 유지하려는 경우). 그것은 당신이 사용해야 auto b = a + 3;하기 때문입니다std::rotateb + 1
Biagio Festa

3

해결책 1

비선형 비교기를 사용한 간단한 접근 방식 .

inline constexpr bool SpecialNumber(const int n) noexcept {
  return n < 7 && 2 < n;
}

void StrangeSortSol1(std::vector<int>* v) {
  std::sort(v->begin(), v->end(), [](const int a, const int b) noexcept {
    const bool aSpecial = SpecialNumber(a);
    const bool bSpecial = SpecialNumber(b);

    if (aSpecial && bSpecial) return b < a;
    if (aSpecial) return false;
    if (bSpecial) return true;
    return b < a;
  });
}

해결책 2

사용 std::algorithm의 (파티션)!

inline constexpr bool SpecialNumber(const int n) noexcept {
  return n < 7 && 2 < n;
}

void StrangeSortSol2(std::vector<int>* v) {
  auto pivot = std::partition(v->begin(), v->end(), std::not_fn(SpecialNumber));
  std::sort(v->begin(), pivot, std::greater{});
  std::sort(pivot, v->end(), std::greater{});
}

성능 고려 사항

파티션 오버 헤드로 인해 두 번째 솔루션이 더 느린 것처럼 보일 수 있습니다. 아마도 현대 프로세서의 캐시 및 미스 브랜치 예측으로 인한 것이 아닙니다.

기준


좋은 컴파일러는 n <= 6 && 3 <= n 대상 CPU에 가장 적합한 것으로 변환해야 하므로 숫자 2와 7을 도입해도 아무런 혼란이 발생하지 않습니다. 왜 참조 대신 벡터에 대한 포인터를 가져 가야합니까?
Ted Lyngmo

'const int number'를 인수 함수로 사용하지 마십시오
Antoine Morrier

1
@AntoineMorrier 왜?
힙 오버 플로우

@HeapOverflow const :)를 사용하지 않고 동일하기 때문에.
Antoine Morrier

@ AntoineMorrier 나는 그것이 같지 않다고 생각합니다. 은하지 않습니다 const함수가 값을 변경하지 않는 것을 독자에게? 이 특별한 경우에는 하나의 라이너가 명확 할 수 있지만 일반적으로 그렇지 않습니다.
힙 오버 플로우
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.