Bir vektörü iki aralık içinde azalan sırada sıralama


14

Diyelim ki bir tamsayı vektörüm var:

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

Sonra azalan sırada sıralıyorum:

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

Bu aşağıdakileri üretir:

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

Şimdi 3, 4, 5 ve 6 sayılarının sonuna kadar taşınmasını ve onlar için azalan düzeni korumasını istiyorum (tercihen sortikinci kez kullanmak zorunda kalmadan ). Yani, işte istediğim şey:

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

Bunun için karşılaştırma işlevini nasıl değiştirmeliyim std::sort?


4
return indices[first] > indices[second]Bunu mu demek istediniz return first < second;?
— acraig5075

2
Basit inen tür için std::greatergelen <functional>senin lambda yerine kullanılabilir. Sorunuza gelince, değerlerinizin istediğiniz şekilde karşılaştırılmasını sağlayan daha ayrıntılı bir karşılaştırıcı yazmak, bunu yapmanın en kolay yolu olabilir.
— sweenish

4
@ acraig5075, azalan sırada olmalıdır return first > second.
— ks1322

1
@ acraig5075 Bir şeyleri özlediğimi hissediyorum ya da insanlar artan ve azalan arasındaki farkı bilmiyor mu?
— sweenish

3
Belki de std :: rotate arıyorsunuz?
— Süper

Yanıtlar:


8

Aldığınız değerler firstve secondöğelerinin öğeleri olduğu için karşılaştırma işleviniz yanlış std::vector. Bu nedenle, bunları endeks olarak kullanmaya gerek yoktur. Yani, değiştirmeniz gerekiyor

return indices[first] > indices[second];

için

return first > second;

Şimdi, çözmeye çalıştığınız problemle ilgili ...

3, 4, 5 ve 6'yı diğer unsurlarla karşılaştırmadan bırakıp yine de birbiriyle karşılaştırabilirsiniz:

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

gösteri


@NutCracker Evet, önce en yüksek kritere sahip olmanın daha iyi olduğunu kabul ediyorum.
— Öbek Taşması

5

Dan Fonksiyonlar standart algoritmaları kütüphaneye gibi iota, sort, find, rotateve copyhayatınızı kolaylaştıracaktır. Örneğin:

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

Çıktı:

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


Yorumlardaki @TedLyngmo, aşağıdakilerle geliştirilebileceği / geliştirilebileceği iyi bir noktaya işaret ediyor:

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

auto b = a + 4;yanlış (önceki snippet ile tutarlılığı korumak istiyorsanız). O olmalı auto b = a + 3;çünkü std::rotatekullandığınızb + 1
— Biagio Festa

3

Çözüm 1

Doğrusal olmayan bir karşılaştırıcı ile doğrudan yaklaşım .

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

Çözüm 2

Kullanarak std::algorithms (bölüm)!

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

Performans Konuları

Bölme yükü nedeniyle ikinci çözüm daha yavaş gibi görünebilir. Muhtemelen modern işlemcilerdeki önbellek ve miss-branch tahmini nedeniyle değil.

Karşılaştırma


Herhangi bir iyi derleyici n <= 6 && 3 <= n , hedef CPU için en iyi olana dönüşmelidir , böylece 2 ve 7 sayılarını değil potansiyel karışıklığı getirerek hiçbir şey kazanmazsınız - ve neden vektör yerine bir referans yerine bir işaretçi alırsınız?
— Ted Lyngmo

`Const int number 'i bağımsız değişken işlevi olarak kullanma
— Antoine Morrier

1
@AntoineMorrier Neden?
— Öbek Taşması

@HeapOverflow Çünkü const kullanmadan aynıdır :).
— Antoine Morrier

@AntoineMorrier Aynı olduğunu düşünmüyorum. Does not constfonksiyon değerini değişmemesini okuyucu söylemek? Bu tek astarlı bir durumda, net olabilir, ancak genel olarak değil.
— Öbek Taşması
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.