データ構造とアルゴリズム-グラフィカルマージソートアルゴリズムとC / C ++コードの実装[推奨コレクション]

1.マージソートの概要

2つの序数のシーケンスを1つの序数のシーケンスに結合することを「マージ」と呼びます。
マージソート(マージソート)は、マージのアイデアを使用して数値のシーケンスをソートすることです。特定の実装によると、マージソートには、「上から下へ」と「下から上へ」の2つの方法が含まれます。

  1. 下から上へのマージと並べ替え:並べ替えるシーケンスを長さ1のいくつかのサブシーケンスに分割し、これらのシーケンスをペアでマージします。長さ2のいくつかの順序シーケンスを取得し、次にこれらのシーケンスをペアでマージします。番号を取得します。長さ4の順序シーケンスの場合、2つずつマージします。1つのシーケンスに直接マージします。このようにして、必要な並べ替え結果を取得します。(下の写真を参照してください)

  2. 上から下へのマージソート:それと「下から上」はソートが反対です。基本的に3つのステップが含まれます
    。①分解–現在の間隔を2つに分割します。つまり、分割点mid =(low + high)/ 2を見つけます
    。②解決–2つのサブ間隔a [low…mid]とa [midを再帰的に実行します。+1 ... high]マージして並べ替えます。再帰の終了条件は、サブインターバルの長さが1であることです。
    ③マージ–2つのソートされたサブ間隔a [low…mid]とa [mid + 1…high]を順序付けられた間隔a [low…high]にマージします。

次の図は、「下から上へ」と「上から下へ」のマージソートの違いを明確に反映しています。
ここに画像の説明を挿入

2つ目は、グラフィックの説明をマージして並べ替える

归并排序(从上往下)代码

/*
 * 将一个数组中的两个相邻有序区间合并成一个
 *
 * 参数说明:
 *     a -- 包含两个有序区间的数组
 *     start -- 第1个有序区间的起始地址。
 *     mid   -- 第1个有序区间的结束地址。也是第2个有序区间的起始地址。
 *     end   -- 第2个有序区间的结束地址。
 */
void merge(int a[], int start, int mid, int end)
{
    
    
    int *tmp = (int *)malloc((end-start+1)*sizeof(int));    // tmp是汇总2个有序区的临时区域
    int i = start;            // 第1个有序区的索引
    int j = mid + 1;        // 第2个有序区的索引
    int k = 0;                // 临时区域的索引

    while(i <= mid && j <= end)
    {
    
    
        if (a[i] <= a[j])
            tmp[k++] = a[i++];
        else
            tmp[k++] = a[j++];
    }

    while(i <= mid)
        tmp[k++] = a[i++];

    while(j <= end)
        tmp[k++] = a[j++];

    // 将排序后的元素,全部都整合到数组a中。
    for (i = 0; i < k; i++)
        a[start + i] = tmp[i];

    free(tmp);
}

/*
 * 归并排序(从上往下)
 *
 * 参数说明:
 *     a -- 待排序的数组
 *     start -- 数组的起始地址
 *     endi -- 数组的结束地址
 */
void merge_sort_up2down(int a[], int start, int end)
{
    
    
    if(a==NULL || start >= end)
        return ;

    int mid = (end + start)/2;
    merge_sort_up2down(a, start, mid); // 递归排序a[start...mid]
    merge_sort_up2down(a, mid+1, end); // 递归排序a[mid+1...end]

    // a[start...mid] 和 a[mid...end]是两个有序空间,
    // 将它们排序成一个有序空间a[start...end]
    merge(a, start, mid, end);
}

配列{80,30,60,40,20,10,50,70}を「マージソートを上から下に」でソートする場合:

  1. 配列{80,30,60,40,20,10,50,70}は、2つの順序付けられたサブ配列{80,30,60,40}と{20,10,50,70}で構成されていると考えてください。2つの順序付けられたサブツリーグループを並べ替えるだけです。
  2. サブ配列{80,30,60,40}は、2つの順序付けられたサブ配列{80,30}と{60,40}で構成されていると考えてください。
    サブ配列{20,10,50,70}は、2つの順序付けられたサブ配列{20,10}と{50,70}で構成されていると考えてください。
  3. サブ配列{80,30}は、2つの順序付けられたサブ配列{80}と{30}で構成されていると考えてください。
    サブ配列{60,40}は、2つの順序付けられたサブ配列{60}と{40}で構成されていると考えてください。
    サブ配列{20,10}は、2つの順序付けられたサブ配列{20}と{10}で構成されていると考えてください。
    サブ配列{50,70}は、2つの順序付けられたサブ配列{50}と{70}で構成されていると考えてください。

归并排序(从下往上)代码

/*
 * 对数组a做若干次合并:数组a的总长度为len,将它分为若干个长度为gap的子数组;
 *             将"每2个相邻的子数组" 进行合并排序。
 *
 * 参数说明:
 *     a -- 待排序的数组
 *     len -- 数组的长度
 *     gap -- 子数组的长度
 */
void merge_groups(int a[], int len, int gap)
{
    
    
    int i;
    int twolen = 2 * gap;    // 两个相邻的子数组的长度

    // 将"每2个相邻的子数组" 进行合并排序。
    for(i = 0; i+2*gap-1 < len; i+=(2*gap))
    {
    
    
        merge(a, i, i+gap-1, i+2*gap-1);
    }

    // 若 i+gap-1 < len-1,则剩余一个子数组没有配对。
    // 将该子数组合并到已排序的数组中。
    if ( i+gap-1 < len-1)
    {
    
    
        merge(a, i, i + gap - 1, len - 1);
    }
}

/*
 * 归并排序(从下往上)
 *
 * 参数说明:
 *     a -- 待排序的数组
 *     len -- 数组的长度
 */
void merge_sort_down2up(int a[], int len)
{
    
    
    int n;

    if (a==NULL || len<=0)
        return ;

    for(n = 1; n < len; n*=2)
        merge_groups(a, len, n);
}

下から上にマージして並べ替えるという考え方は、「下から上にマージして並べ替える」の正反対です。次の図に示すように:
ここに画像の説明を挿入
配列{80,30,60,40,20,10,50,70}を「マージして下から上に並べ替える」で並べ替える場合:

  1. 配列{80,30,60,40,20,10,50,70}は、8つの順序付けられたサブ配列{80}、{30}、{60}、{40}、{20}、{10 }、{50}および{70}。
  2. これらの8つの順序付けられたサブシーケンスをペアで結合します。4つの順序付けられたサブツリー列{30,80}、{40,60}、{10,20}、および{50,70}を取得します。
  3. これらの4つの順序付けられたサブシーケンスをペアで結合します。2つの順序付けられたサブツリー列{30,40,60,80}と{10,20,50,70}を取得します。
  4. これらの2つの順序付けられたサブシーケンスをペアで結合します。1つの順序付けられたサブツリー列{10,20,30,40,50,60,70,80}を取得します。

編集者は私自身のlinuxC / C ++言語技術交換グループを推奨しています:[ 1106675687 ]グループファイルで共有する方が良いと思う学習本とビデオ資料をいくつかまとめました。必要に応じて追加できます。
ここに画像の説明を挿入

第三に、マージソートの時間計算量と安定性


マージソートの時間計算量マージソートの時間計算量はO(N lgN)です。
ソートされているシーケンスにN個の番号があるとします。トラバーサルの時間計算量はO(N)です。トラバーサルはいくつ必要ですか?
マージソートの形式は二分木であり、トラバースする必要がある回数は二分木の深さであり、完全な二分木によれば、その時間計算量はO(N
lgN)であると結論付けることができます。

マージソートの安定性
マージソートは安定したアルゴリズムであり、安定したアルゴリズムの定義を満たしています。
アルゴリズムの安定性-シーケンスにa [i] = a [j]があると仮定します。ソート前の場合、a [i]はa [j]の前にあり、ソート後、a [i]はまだa [j]の前にあります。そうすれば、このソートアルゴリズムは安定しています!

4、マージソートの実装

マージソートの3つの実装を以下に示します:C、C ++、およびJava。これら3つの実装の原則と出力結果は同じです。各実装には、「トップダウンマージソート」と「ボトムアップマージソート」の2つの形式が含まれます。マージ
ソートC実装
実装コード(merge_sort.c)

View Code


マージソートC ++実装実装コード(MergeSort.cpp)

View Code


マージソートJava実装コード(MergeSort.java)

 View Code

上記の3つの実装の原理と出力結果は同じです。それらの出力は次のとおりです。

before sort:80 30 60 40 20 10 50 70 
after  sort:10 20 30 40 50 60 70 80 

おすすめ

転載: blog.csdn.net/m0_50662680/article/details/113055011