アルゴリズムをソート - マージソート

基本的な考え方

基本的な考え方は、ソートマージすることである:最初の[0..N-1]長さn 1のソートされたリストとして、隣接するK(≧2)のペアは、サブリストをマージ命じ、順序付けられたサブテーブルの長さkの/ K Nを得、次いで、順序付け、マージサブリストを続け、そう繰り返し続け、順序付けられたサブテーブルの長さK2のN / K2を取得し、最終的な長さnを与えます順序付きリスト。

即ち、K = 2は、二つに行う場​​合の方法ソートマージ呼ばれるサブテーブルに隣接して順序付けられた合併しました。K> 2、すなわち、マージ操作が隣接して順序付けられたサブテーブルを複数行う場合には、マージソートマルチプレクサと呼ばれます。

 例えば

2,5,1,7,10,6,9,4,3,8シーケンス{}ボトムアップのための発注処理以下に示すように、角括弧内の順序付けられた図のシーケンスです。

 

  サイクルlog2n時間は、長順次1,2、...、log2nを捕捉します。たびに、次の手順を実行します。

  ①分解:長さの複数のサブシーケンス長に元の配列。

  ②副問題を解決する2つの隣接するサブシーケンス・コールは、順序付けられたシーケンスに組み合わせるアルゴリズムをマージします。

  ③合成:全配列が配列Aに格納されているので、分類プロセスは、in situでマージステップ何のアクションも行われます。

トップダウンの注文プロセスは、以下に示します

  ①分解:配列[low..high 2つに、即ち、中間=(ハイ+ロー)/ 2を求め、再帰的2つのサブ[low..mid]と[中間+ 1 .. ]高は分解を実行し続けます。長さ1のサブシーケンスである終了条件(テーブル要素としてサブテーブルを注文しなければなりません)。

  ②合成:分解コントラスト、二つのサブソート配列[low..mid]と[中間+ 1..high]は[low..high]の順序付けられたシーケンスにマージ。

 アルゴリズムコード

 1 //对区间a[low..mid]和区间a[mid+1..high]进行排序
 2 void Merge(int a[], int low, int mid, int high)
 3 {
 4     int i = low, j = mid + 1;
 5     int k = 0;
 6     int *temp = (int *)malloc((high - low + 1) * sizeof(int));
 7     while (i <= mid && j <= high)
 8         if (a[i] <= a[j]) //将第1子表中的元素放入temp中
 9         {
10             temp[k] = a[i];
11             i++;
12             k++;
13         }
14         else //将第2子表中的元素放入temp中
15         {
16             temp[k] = a[j];
17             j++;
18             k++;
19         }
20     while (i <= mid) //将第1子表余下部分复制到temp
21     {
22         temp[k] = a[i];
23         i++;
24         k++;
25     }
26     while (j <= high) //将第2子表余下部分复制到temp
27     {
28         temp[k] = a[j];
29         j++;
30         k++;
31     }
32     for (k = 0, i = low; i <= high; k++, i++) //将temp复制回a中对应的位置
33         a[i] = temp[k];
34     free(temp); //释放temp所占内存空间
35 }

 自底向上的二路归并排序算法

 1 void MergePass(int a[], int length, int n) //一趟二路归并排序
 2 {
 3     int i;
 4 
 5     for (i = 0; i + 2 * length - 1 < n; i = i + 2 * length) //归并length长的两相邻子表
 6     {
 7         Merge(a, i, i + length - 1, i + 2 * length - 1);
 8     }
 9 
10     if (i + length - 1 < n) //余下两个子表,后者长度小于length
11     {
12         Merge(a, i, i + length - 1, n - 1); //归并这两个子表
13     }
14 }
15 
16 void MergeSort(int arr[], int n) //二路归并算法
17 {
18     for (int length = 1; length < n; length = 2 * length)
19     {
20         MergePass(arr, length, n);
21     }
22 }

 自顶向下的二路归并排序算法

 1 void MergeSort(int a[], int low, int high)
 2 //二路归并算法
 3 {
 4     int mid;
 5     if (low < high) //子序列有两个或以上元素
 6     {
 7         mid = (low + high) / 2;          //取中间位置
 8         MergeSort2(a, low, mid);      //对a[low..mid]子序列排序
 9         MergeSort2(a, mid + 1, high); //对a[mid+1..high]子序列排序
10         Merge(a, low, mid, high);     //将两子序列合并,见前面的算法
11     }
12 }

 算法分析

 对于上述二路归并排序算法,当有n个元素时,需要log2n趟归并,每一趟归并,其元素比较次数不超过n-1,元素移动次数都是n,因此归并排序的时间复杂度为O(nlog2n)。

 

おすすめ

転載: www.cnblogs.com/WindSun/p/11360870.html