目次
I.はじめに
(1) 分割統治アルゴリズム
マージソートは実際には分割統治アルゴリズムであるため、マージソートを理解する前に、分割統治アルゴリズムとは何かを見てみましょう。アルゴリズム設計では、分割統治アルゴリズムと呼ばれる分割統治戦略を導入します。その本質は、大規模な問題をいくつかの小規模な同一のサブ問題に分解し、分割統治することです。
(2) 分割統治アルゴリズムの問題解決方法
1. 分解:
解決する問題を、元の問題と同じ形式のいくつかの小さな独立したサブ問題に分解します。
2. ガバナンス:
各サブ問題を解決します。各副問題は元の問題と同じ形をしていますが、規模が小さいため、副問題を十分に細かく分割すると、簡単な方法で解決できます。
3.マージ
元の問題の要件に従って、サブ問題のソリューションをレイヤーごとに組み合わせて、元の問題のソリューションを形成します。
2.マージソート
1. 問題分析
マージソートは、比較的安定したソート方法です。その基本的な考え方は、ソートされる要素をほぼ同じサイズの 2 つのサブシーケンスに分解することです。分解が容易でない場合は、部分列に含まれる要素の数が 1 になるまで、得られた部分列を分解し続けます。個々の要素のシーケンス自体が順序付けられているため、この時点でマージして完全な順序付けられたシーケンスを取得できます。
2. アルゴリズム設計
(1) 分解:
並べ替える要素を、ほぼ同じサイズの 2 つのサブシーケンスに分割します。
(2) ガバナンス:
2 つのサブシーケンスをマージして並べ替えます。
(3) マージ:
並べ替えられた順序付きサブシーケンスをマージして、最終的な順序付きシーケンスを取得します。
3. アルゴリズム分析
まず、最初に順序付けされていないシーケンス (42、15、20、6、8、38、50、12) を指定し、以下のフローチャートに示すようにマージ ソート シーケンスを実行します。
ステップ 1: まず、ソートする要素をほぼ同じサイズの 2 つのシーケンスに分割します。
ステップ 2: サブシーケンスをほぼ同じサイズの 2 つのサブシーケンスに分割します。
ステップ 3: 1 つの要素に分解されるまで、このように続けます。この時点で、1 つの要素を含むサブシーケンスはすべて順番に並んでいます。
ステップ 4: マージ操作を実行して、2 つの順序付けられたサブシーケンスを順序付けられたシーケンスにマージし、すべての要素が順序付けられたシーケンスにマージされるまで繰り返します。
たとえば、以下では (4、9、15、24、30、2、6、18、20) の順序で説明します。
(1) 初期化: i = low、j = mid+1、mid = (low+hight)/2、補助配列 b に適用
int* b = new int[hight - low + 1]; //用 new 申请一个辅助函数
int i = low, j = mid + 1, k = 0; // k为 b 数组的小标
(2) 次に、a [i] と b[j] を比較し、小さい方の要素を b 配列に入れ、対応するポインターを i > mid または j > hight まで後方に移動します。
while (i <= mid && j <= hight)
{
if (a[i] <= a[j])
{
b[k++] = a[i++]; //按从小到大存放在 b 数组里面
}
else
{
b[k++] = a[j++];
}
}
次の図に示すように、最初の比較 a[i]=4 と a[j]=2 を実行し、小さい方の要素 2 を配列 b、j++、k++ に入れます。
次の図に示すように、2 番目の比較 a[i]=4 と a[j]=6 を実行し、小さい方の要素 4 を配列 b、i++、k++ に入れます。
次の図に示すように、3 番目の比較 a[i]=9 と a[j]=6 を実行し、小さい方の要素 6 を配列 b、j++、k++ に入れます。
次の図に示すように、4 番目の比較 a[i]=9 と a[j]=18 を実行し、小さい方の要素 9 を配列 b、i++、k++ に入れます。
次の図に示すように、5 番目の比較 a[i]=15 と a[j]=18 を実行し、小さい方の要素 15 を配列 b、i++、k++ に入れます。
次の図に示すように、6 番目の比較 a[i]=24 と a[j]=18 を実行し、小さい方の要素 18 を配列 b、j++、k++ に入れます。
次の図に示すように、7 番目の比較 a[i]=24 と a[j]=20 を実行し、小さい要素 20 を配列 b、j++、k++ に入れます。
この時点で j>hight となり、while ループは終了しますが、a 配列の残りの要素 (i<mid) は直接 b 配列に入れることができます。以下に示すように:
while (i <= mid) // j 序列结束,将剩余的 i 序列补充在 b 数组中
{
b[k++] = a[i++];
}
while (j <= hight)// i 序列结束,将剩余的 j 序列补充在 b 数组中
{
b[k++] = a[j++];
}
ここで、b 配列の要素を a 配列に代入してから、b 配列を破棄します。
for (int i = low; i <= hight; i++) //将 b 数组的值传递给数组 a
{
a[i] = b[k++];
}
delete[]b; // 辅助数组用完后,将其的空间进行释放(销毁)
(3) 再帰的な形でのマージとソート
void mergesort(int* a, int low, int hight) //归并排序
{
if (low < hight)
{
int mid = (low + hight) / 2;
mergesort(a, low, mid); //对 a[low,mid]进行排序
mergesort(a, mid + 1, hight); //对 a[mid+1,hight]进行排序
merge(a, low, mid, hight); //进行合并操作
}
}
3.ACコード
#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cmath>
using namespace std;
void merge(int* a, int low, int mid, int hight) //合并函数
{
int* b = new int[hight - low + 1]; //用 new 申请一个辅助函数
int i = low, j = mid + 1, k = 0; // k为 b 数组的小标
while (i <= mid && j <= hight)
{
if (a[i] <= a[j])
{
b[k++] = a[i++]; //按从小到大存放在 b 数组里面
}
else
{
b[k++] = a[j++];
}
}
while (i <= mid) // j 序列结束,将剩余的 i 序列补充在 b 数组中
{
b[k++] = a[i++];
}
while (j <= hight)// i 序列结束,将剩余的 j 序列补充在 b 数组中
{
b[k++] = a[j++];
}
k = 0; //从小标为 0 开始传送
for (int i = low; i <= hight; i++) //将 b 数组的值传递给数组 a
{
a[i] = b[k++];
}
delete[]b; // 辅助数组用完后,将其的空间进行释放(销毁)
}
void mergesort(int* a, int low, int hight) //归并排序
{
if (low < hight)
{
int mid = (low + hight) / 2;
mergesort(a, low, mid); //对 a[low,mid]进行排序
mergesort(a, mid + 1, hight); //对 a[mid+1,hight]进行排序
merge(a, low, mid, hight); //进行合并操作
}
}
int main()
{
int n, a[100];
cout << "请输入数列中的元素个数 n 为:" << endl;
cin >> n;
cout << "请依次输入数列中的元素:" << endl;
for (int i = 0; i < n; i++)
{
cin >> a[i];
}
mergesort(a, 0, n-1);
cout << "归并排序结果" << endl;
for (int i = 0; i < n; i++)
{
cout << a[i] << " ";
}
cout << endl;
return 0;
}
第四、相互励まし
分割統治アルゴリズムについての私の理解は次のとおりです: マージ ソート. 理解していない友人や問題を見つけた友人がいる場合は, コメント欄で教えてください. 同時に, 理解を更新し続けます.分割統治法について、今後ともご注目ください。! ! ! ! ! ! !