分割して征服する:マージソート
分割して征服する:一般的な手順
- 元の問題を複数のサブ問題に分解します
- サブ問題を解決する各サブ問題を再帰的に解決する
- 問題の解決策を組み合わせて、結果を元の問題の解決策にマージします
マージソート
基本的な考え方:
2つ以上の順序付けられたサブシーケンスを順序付けられたシーケンスに「マージ」します。内部ソートでは、通常、双方向マージソートが使用されます。つまり、隣接する2つのレコードは順序付けられたサブシーケンスです。
アルゴリズムフロー:
-
配列
A[1,n]
スケジューリング問題分解へA[1,n/2]
とA[n/2 +1,n]
スケジューリング -
サブ問題を再帰的に解決して、 2つの順序付けられたサブアレイを取得します
-
2つの順序付けられたサブ配列を1つの順序付けられた配列に結合します
マージソート:分解の配列、手持ち所有、一緒に解決され、ソート
手順は次のとおりです(小さいものから大きいものへ)。
void merge_sort(int *A, int L, int R, int *T){
if(R-L > 1){
int M = L + (R-L)/2; //划分
int l = L, m = M, i = L;
merge_sort(A, L, M, T); //递归求解
merge_sort(A, M, R, T); //递归求解
while(l<M || m<R){
if(m>=R || (l<M && A[l]<=A[m]))
T[i++] = A[l++]; //从左半数组复制到临时空间
else
T[i++] = A[m++]; //从右半数组复制到临时空间
}
for(i=L; i<R; i++) //从辅助空间复制回 A 数组
A[i] = T[i];
}
}
n個のレコードをマージおよびソートする時間の複雑さはO(nlog 2 n)です。これは:
- 各マージの時間の複雑さはO(n)です。
- ログの合計の2 n個のパスが必要とされます。
例:
タイトルの説明
長さnの整数シーケンスが与えられます。このシリーズを最小から最大にソートするには、マージソートを使用してください。そして、ソートされたシーケンスを順番に出力します。
入力フォーマット
2行の入力があり、最初の行には整数nが含まれています。
2行目には、番号シーケンス全体を表すn個の整数(すべての整数は1〜109の範囲)が含まれています。
出力形式
出力は、n個の整数を含む行であり、ソートされた番号のシーケンスを示します。
データ範囲
1≤n≤100000
入力例:
5
3 1 2 4 5
サンプル出力:
1 2 3 4 5
コード:
#include <iostream>
#include <cstdio>
using namespace std;
const int N = 1e6 + 10;
int q[N],T[N];
void merge_sort(int *A, int L, int R, int *T){
if(R-L > 1){
int M = L + (R-L)/2;
int l = L, m = M, i = L;
merge_sort(A, L, M, T);
merge_sort(A, M, R, T);
while(l<M || m<R){
if(m>=R || (l<M && A[l]<=A[m]))
T[i++] = A[l++];
else
T[i++] = A[m++];
}
for(i=L; i<R; i++)
A[i] = T[i];
}
}
int main(){
int n;
scanf("%d", &n);
for (int i = 0; i < n; i++)
scanf("%d",&q[i]);
merge_sort(q, 0, n, T);
for (int i = 0; i < n; i++)
printf("%d ",q[i]);
return 0;
}