2つの範囲内でベクトルを降順に並べ替える


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を最後に移動し、それらの降順を維持したいとします(できればsort2回目に使用する必要はありません)。つまり、ここに私が欲しいものがあります:

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::greaterfrom <functional>をラムダの代わりに使用できます。あなたの質問に関しては、あなたの値があなたが望む方法で比較することを保証するより詳細なコンパレータを書くことはそれを行う最も簡単な方法かもしれません。
スウィーニッシュ

4
@ acraig5075、降順である必要がありますreturn first > second
ks1322

1
@ acraig5075何かが足りないような気がしますか、それとも昇順降順の違いが分からないのですか?
13:22にスウィーニッシュ

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

機能標準的なアルゴリズムライブラリのようなiotasortfindrotateそして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::rotate、使用b + 1
ビアージョフェスタ

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::algorithms(パーティション)を使用!

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

パフォーマンスに関する考慮事項

パーティションのオーバーヘッドのため、2番目のソリューションの方が遅いように見えます。最近のプロセッサのキャッシュと分岐予測が原因で、おそらくそうではありません。

基準


優れたコンパイラーは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.