C++のソート・比較順に関するまとめ

C++

基本のソート(昇順)

std::sort()

std::vector<int> seq = {5, 2, 4, 1, 3};
std::sort(seq.begin(), seq.end());

for (int i = 0; i < seq.size(); i++) std::cout << seq[i] << " ";//1 2 3 4 5 

ranges::sort()

std::vector<int> seq = {5, 2, 4, 1, 3};

//これはstd::sort(seq.begin(), seq.end())と同じ意味
std::ranges::sort(seq);

for (int i = 0; i < seq.size(); i++) std::cout << seq[i] << " ";//1 2 3 4 5 

ranges::C++20から対応しています。

ソート(降順)

std::sort()

std::vector<int> seq = {5, 2, 4, 1, 3};
std::sort(seq.begin(), seq.end(), std::greater<int>());

for (int i = 0; i < seq.size(); i++) std::cout << seq[i] << " ";//5 4 3 2 1 

ranges::sort()

std::vector<int> seq = {5, 2, 4, 1, 3};

//これはstd::sort(seq.begin(), seq.end(), std::greater<int>())と同じ意味
std::ranges::sort(seq, std::greater());
    
for (int i = 0; i < seq.size(); i++) std::cout << seq[i] << " ";//5 4 3 2 1

自作クラスのソート

自作クラスでソートをするには “何を基準にソートするか?” を定義する必要があるので
クラスの “比較演算子のオーバーロード” をすることで定義します
昇順なら<, 降順なら>をオーバーロードします(似てるので注意です!)

昇順ソート (クラス部分のコード)

class my_class {
  public:
  int id;
  std::string name;

  //idで昇順ソート
  bool operator<(const my_class &other) const {
    return id < other.id;
  }
};

降順ソート (クラス部分のコード)

class my_class {
  public:
  int id;
  std::string name;

  //idで降順ソート
  bool operator>(const my_class &other) const {
    return id > other.id;
  }
};

/*
greater<>()の<>には、クラス名をいれてください
std::sort(seq.begin(), seq.end(), std::greater<my_class>());
*/

sort()の呼び出し時に、比較方法を与える(ラムダ式)

std::sort()の “三番目の引数にラムダ式を与える” 方法を紹介します
(std::ranges::sort()なら二番目の引数に与えればよいです)
T := 比較される型

//ラムダ式(戻り値がbool)
[](T 左側要素, T 右側要素)->bool {
    /*ここに比較方法を書く*/
}
std::vector<int> seq = {5, 2, 4, 1, 3};
/*
3で割った余りが小さいもの順にソート
(ただし、割った余りが同じ場合は数の大きさで昇順ソート)
*/
std::sort(seq.begin(), seq.end(), [](const int &left, const int &right)->bool {
  int mod_left = left % 3;
  int mod_right = right % 3;
  if (mod_left == mod_right) return left < right;
  else return mod_left < mod_right;
});
    
for (int i = 0; i < seq.size(); i++) std::cout << seq[i] << " ";//3 1 4 2 5

priority_queueの優先順位を定義する

単なる昇順または降順に取り出される宣言

//大きいものの方が優先度が高くなる宣言
std::priority_queue<int> pq_1;

//小さいものの方が優先度が高くなる宣言
std::priority_queue<int, std::vector<int>, std::greater<int> > pq_2;

自分で優先度の付け方を決める方法

/*
絶対値が大きいものほど優先順位が高いpriority_queueを宣言
(例として絶対値が大きいものにしただけで、自由に決めれます)
*/
std::priority_queue<int, std::vector<int>, decltype([](int left, int right)->bool {
  return abs(left) < abs(right);
})> pq;

for (auto x : {-5, -2, 4, 1, 3}) pq.push(x);

while (!pq.empty()) {
    std::cout << pq.top() << " ";//-5 4 3 -2 1
    pq.pop();
}

ほかにも色々ある!! ソート系関数

安定ソートをする → stable_sort()

ソートには安定ソート不安定ソートがあり、これは安定ソートをするための関数です。
{安定・不安定}というのは“比較のための値で、同じ値が複数ある場合”にそれらをソートした際に
元の位置関係が保たれるかどうか
のことです

例えば、先ほどこの記事で書いた”自作クラスで比較する場合”で考えてみましょう

std::vector<my_class> seq = {{4, "C"}, {1, "A"}, {3, "D"}, {2, "B"}, {3, "E"}};
/*
これは不安定ソート!!
3という値が2つあるため、これらの順番(位置関係)が保証されない。(うまくいくこともあるが...)
*/
std::sort(seq.begin(), seq.end());

これらの元の位置関係を保証してくれるのがstablesort()です

std::vector<my_class> seq = {{4, "C"}, {1, "A"}, {3, "D"}, {2, "B"}, {3, "E"}};
std::stable_sort(seq.begin(), seq.end());

ソート済みかを返す → is_sorted()

昇順ソートされているか?

std::vector<int> seq = {5, 2, 4, 1, 3};

std::cout << std::boolalpha << std::ranges::is_sorted(seq) << std::endl;//false

std::ranges::sort(seq);

std::cout << std::boolalpha << std::ranges::is_sorted(seq) << std::endl;//true

降順ソートされているか?

std::vector<int> seq = {5, 2, 4, 1, 3};

std::cout << std::boolalpha << std::ranges::is_sorted(seq, std::greater<int>()) << std::endl;//false

std::ranges::sort(seq, std::greater<int>());

std::cout << std::boolalpha << std::ranges::is_sorted(seq, std::greater<int>()) << std::endl;//true

他にも学び次第追記する予定です。

コメント

タイトルとURLをコピーしました