Sắp xếp một vectơ theo thứ tự giảm dần trong hai phạm vi


14

Nói rằng tôi có một vectơ số nguyên:

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

Sau đó, tôi sắp xếp nó theo thứ tự giảm dần:

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]);

Điều này tạo ra như sau:

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

Bây giờ tôi muốn có các số 3, 4, 5 và 6 được di chuyển đến cuối và giữ thứ tự giảm dần cho chúng (tốt nhất là không phải sử dụng sortlần thứ hai). Tức là đây là những gì tôi muốn:

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

Làm thế nào tôi nên sửa đổi chức năng so sánh của std::sortđể đạt được điều đó?


4
return indices[first] > indices[second]Ý bạn là return first < second;sao?
acraig5075

2
Đối với một loại giảm dần đơn giản, std::greatertừ <functional>có thể được sử dụng thay cho lambda của bạn. Đối với câu hỏi của bạn, viết một bộ so sánh dài hơn để đảm bảo các giá trị của bạn so sánh theo cách bạn muốn có thể là cách dễ nhất để làm điều đó.
sweenish

4
@ acraig5075, theo thứ tự giảm dần return first > second.
ks1322

1
@ acraig5075 Tôi cảm thấy như mình đang thiếu thứ gì đó, hoặc mọi người không biết sự khác biệt giữa tăng dầngiảm dần ?
sweenish

3
Có lẽ bạn đang tìm kiếm std :: rotation ?
siêu

Câu trả lời:


8

Hàm so sánh của bạn sai vì các giá trị bạn nhận được firstsecondlà các phần tử của std::vector. Do đó, không cần sử dụng chúng như các chỉ số. Vì vậy, bạn cần thay đổi

return indices[first] > indices[second];

đến

return first > second;

Bây giờ, liên quan đến vấn đề bạn cố gắng giải quyết ...

Bạn có thể bỏ 3, 4, 5 và 6 so với các yếu tố khác và vẫn so sánh nó với nhau:

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;
    }
);

Bản giới thiệu


@NutCracker Vâng, tôi đồng ý rằng nó sẽ đẹp hơn để có tiêu chí hàng đầu trước tiên.
Heap tràn

5

Chức năng từ thư viện các thuật toán tiêu chuẩn như iota, sort, find, rotatecopysẽ làm cho cuộc sống của bạn dễ dàng hơn. Ví dụ của bạn đi xuống:

#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;
}

Đầu ra:

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


@TedLyngmo trong các bình luận cho thấy điểm hay mà nó có thể / nên được cải thiện với:

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

auto b = a + 4;là sai (nếu bạn muốn giữ sự nhất quán với đoạn mã trước). Nó nên là auto b = a + 3;bởi vì trong std::rotatebạn sử dụngb + 1
Biagio Festa

3

Giải pháp 1

Cách tiếp cận đơn giản với một bộ so sánh phi tuyến tính .

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;
  });
}

Giải pháp 2

Sử dụng std::algorithms (phân vùng)!

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{});
}

Cân nhắc hiệu suất

Có vẻ như giải pháp thứ hai chậm hơn do chi phí quá cao của phân vùng. Có lẽ là không, vì bộ nhớ cache và dự đoán sai nhánh trong các bộ xử lý hiện đại.

Điểm chuẩn


Bất kỳ trình biên dịch tốt nào cũng nên chuyển đổi n <= 6 && 3 <= n thành bất cứ thứ gì hoạt động tốt nhất cho CPU mục tiêu để bạn không thu được gì bằng cách giới thiệu các số 2 và 7 nhưng có thể gây nhầm lẫn - và tại sao lại lấy một con trỏ tới vectơ thay vì tham chiếu?
Ted Lyngmo

Đừng sử dụng `const int number` làm hàm đối số
Antoine Morrier

1
@AntoineMorrier Tại sao?
Heap Overflow

@HeapOverflow Vì nó giống nhau mà không sử dụng const :).
Antoine Morrier

@AntoineMorrier Tôi không nghĩ nó giống nhau. Không phải constngười đọc nói với hàm rằng hàm không thay đổi giá trị sao? Trong trường hợp cụ thể này của một lớp lót có thể rõ ràng, nhưng nói chung là không.
Heap tràn
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.