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.