LoginSignup
0
0

More than 5 years have passed since last update.

ソート学習

Last updated at Posted at 2018-08-14
#include<iostream>
#include<algorithm>
using namespace std;

int main(){
    int N;
    int a[100000];
    cin >> N;
    for (int i = 0; i < N; ++i)cin >> a[i];
    sort(a, a + N);//a[0;N]を小さい順にソート
    for (int i = 0; i < N; ++i)cout << a[i] << " ";
        return 0;
}

入力として
8
12 66 3 23 51 89 15 37
を与えると出力結果として
3 12 15 23 37 51 66 89
が返ってくる

vectorでもソートすると

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;

int main(){
    int N;     //要素数
    vector<int>a;
    cin >> N;
    for (int i = 0; i < N; ++i) {
        int a_temp;
        cin >> a_temp;
        a.push_back(a_temp);
    }
    sort(a.begin(), a.end());

    for (int i = 0; i < N; ++i)cout << a[i];
}

a.push_back(要素)でaに要素を挿入することができる大きい順にソートしたい時は

sort(a.begin(), a.end(), greater<int>()); 

とすればよい
特殊な比較関数(ここでは50と近い順でやってみる)で比較したい時は

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;

bool cmp(int a, int b) {
    return abs(a - 50) < abs(b - 50);
}
int main(){
    int N;     //要素数
    vector<int>a;
    cin >> N;
    for (int i = 0; i < N; ++i) {
        int a_temp;
        cin >> a_temp;
        a.push_back(a_temp);
    }
    sort(a.begin(), a.end(),cmp);

    for (int i = 0; i < N; ++i)cout << a[i];
}

まずは素朴なソートから入って行きます。挿入ソートは、

前から順番に、i 番目の要素を適切な場所へ挿入することを繰り返す
というアルゴリズムです。「41352」に対する動作例はこんな感じです。1 個目の「4」はそのままで、2 個目の「1」を適切な場所まで前に持っていきます。次に 3 個目の「3」を適切な場所まで前に持っていきます。次に 4 個目の「5」を適切な場所まで前に持っていきます (「5」はその手前の4より既に大きいので結局動きません)。最後に 5 個目の「2」を適切な場所まで前に持っていきます。

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;

int main() {
    int n;
    cin >> n;
    vector<int>a(n);
    for (int i = 0; i < n; i++) {
        cin >> a[i];
    }
    /*挿入前の配列を出力してみる*/
    cout << "Before:";
    for (int i=0; i < n; i++)cout << a[i] << " ";
    cout << endl;
    /*挿入ソート*/
    for (int i = 1; i < n; i++) {
        int v = a[i];
    //vを挿入する適切な場所jを探す
    int j = i;
    for (; j > 0; --j) {
        if (a[j - 1] > v) {//vより大きい奴は1個後ろに移す
            a[j] = a[j - 1];
        }
        else break;//v以下になったら止める
    }
    a[j] = v;//最後にj番目にvを挿入
    /*各ステップの配列を出力してみる*/
    cout << "after step" << i << ":";
    for (int i = 0; i < n; i++)cout << a[i] << " ";
    cout << endl;
   }
    return 0;
}

マージソートは、再帰を利用したソートアルゴリズムです。配列を半分に分けて、それぞれをソートしておいて、その 2 つをマージすることを繰り返します。MergeSort(a, left, mid) は配列の左半分をソートして、MergeSort(a, mid, right) は配列の右半分をソートします。そしてそれらをマージします。

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;

void MergeSort(vector<int> &a, int left, int right) {
    if (right - left == 1)return;
    int mid = left + (right - left) / 2;
    //左半分[left,mid)をソート
    MergeSort(a, left, mid);
    //右半分[mid,right)をソート
    MergeSort(a, mid, right);
    //一旦「左」と「右」のソート結果をコピーしておく(右側は左右反転)
    vector<int>buf;
    for (int i = left; i < mid; ++i)buf.push_back(a[i]);
    for (int i = right - 1; i >= mid; --i)buf.push_back(a[i]);
    //マージする
    int iterator_left = 0; //左側のイテレータ
    int iterator_right = (int)buf.size() - 1;//右側のイテレータ
    for (int i = left; i < right; ++i) {
        //左側採用
        if (buf[iterator_left] <= buf[iterator_right]) {
            a[i] = buf[iterator_left++];
        }
        //右側採用
        else {
            a[i] = buf[iterator_right--];
        }
    }
}

int main() {
    int n;//要素数
    cin >> n;
    vector<int>a(n);//整列したい配列ベクトル(サイズをnに初期化)
    for (int i = 0; i < n; ++i) {
        cin >> a[i];//整列したい配列を取得
    }
    /*マージソート*/
    MergeSort(a, 0, n);
    return 0;
}

仕組みはわかるけどコード書くのがまだ慣れないむずい、、

次はクイックソート
QuickSort(a, left, right): 配列 a の left 〜 right 部分 a[left:right] をソートする

right - left == 1 だったらリターンする (要素数 1 なので)
配列 a[left:right] の要素を 1 つ選ぶ (pivot と呼ぶ)
a[left:right] を適切に並び替えて、pivot より左側は pivot 未満、右側は pivot 以上になるようにする (このとき、pivot の来る index を i とする)
QuickSort(a, left, i)
QuickSort(a, i+1, right)
という再帰関数を用意しておいて、

QuickSort(a, 0, n)
を呼ぶ

#include<iostream>
#include<vector>
using namespace std;

void QuickSort(vector<int>&a, int left, int right) {
    if (right - left <= 1)return;
    int pivot_index = (left + right) / 2;
    int pivot = a[pivot_index];
    swap(a[pivot_index], a[right - 1]);

    int i = left;
    for (int j = left; j < right - 1; ++j) {
        if (a[j] < pivot) {
            swap(a[i++], a[j]);
        }
    }
    swap(a[i], a[right - 1]);
    QuickSort(a, left, i);
    QuickSort(a, i + 1, right);
}
int main() {
    int n;
    cin >> n;
    vector<int>a(n);
    for (int i = 0; i < n; ++i) {
        cin >> a[i];
    }
    QuickSort(a, 0, n);

    return 0;
}

ヒープの実装例

#include<iostream>
#include<vector>
using namespace std;

struct Heap {
    vector<int>heap;
    Heap(){}
    void push(int v) {
        heap.push_back(v);
        int i = (int)heap.size() - 1;
        while (i > 0) {
            int p = (i - 1) / 2;
            if (heap[p] >= v)break;
            heap[i] = heap[p];
            i = p;
        }
        heap[i] = v;
    }
    int top() {
        if (!heap.empty())return heap[0];
        else return -1;
    }
    void pop() {
        if (heap.empty())return;
        int v = heap.back();
        heap.pop_back();
        int i = 0;
        while (i * 2 + 1 < (int)heap.size()) {
            int child1 = i * 2 + 1, child2 = i * 2 + 2;
            if (child2 < (int)heap.size() && heap[child2] > heap[child1])child1 = child2;
            if (heap[child1] <= v)break;
            heap[i] = heap[child1];
            i = child1;
        }
        heap[i] = v;
    }
};
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0