マージソートアルゴリズムを理解する

    このチュートリアルでは、マージソートアルゴリズムについて学習します。さらに、C言語でのマージソートの例があります。
    マージソートは、分割統治アルゴリズムの原理に基づく最も一般的なソートアルゴリズムの1つです。
    ここで、問題は複数のサブ問題に分けられます。各サブ問題は個別に解決されます。最後に、サブ問題を組み合わせて最終的な解決策を形成します。
ここに画像の説明を挿入します

分割統治戦略

    分割統治法を使用して、問題をサブ問題に分割します。各サブ問題の解決策の準備ができたら、サブ問題の結果を「結合」して、主要な問題を解決します。
    配列Aを並べ替える必要があるとします。サブ問題は、この配列のサブパーツを、インデックスpから始まり、A [p ... r]で示されるインデックスrで終わるように並べ替えることです。
    分割
    qがpとrの中間点である場合、サブ配列A [p ... r]を2つの配列A [p ... q]とA [q + 1、r]に分割できます。
    処理
    処理ステップでは、サブ配列A [p ... q]とA [q + 1、r]を並べ替えようとします。基本レベルにまだ分割していない場合は、2つのサブ配列を再度分割して、並べ替えを試みます。
    組み合わせと
    処理のステップの後、2つのソートされたサブ配列A [p ... q]とA [q + 1、r]を取得します。これら2つの配列を結合した後、ソートされた配列A [p ... rを取得します。 ]。

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

    マージソート関数は、サイズ1のサブ配列(p == r)でマージソートを実行しようとする段階に達するまで、配列を繰り返し半分に分割します。
    その後、マージ関数が機能し、配列全体がマージされるまで、ソートされた配列をより大きな配列にマージします。

MergeSort(A, p, r):
    if p > r 
        return
    q = (p+r)/2
    mergeSort(A, p, q)
    mergeSort(A, q+1, r)
    merge(A, p, q, r)

    配列全体をソートするには、MergeSort(A、0、length(A)-1)を呼び出す必要があります。
    次の図に示すように、マージソートアルゴリズムは、1つの要素を含む配列の基本的な状況が得られるまで、配列を再帰的に半分に分割します。その後、マージ関数はソートされたサブ配列を選択し、それらをマージして配列全体を徐々にソートします。
ここに画像の説明を挿入します

マージソートのマージステップ

    すべての再帰的アルゴリズムは、基本的な状況と、基本的な状況の結果を組み合わせる機能に依存しています。マージソートについても同じことが言えます。マージソートアルゴリズムの最も重要な部分は、マージステップです。
    マージステップは、2つのソートされたリスト(配列)を1つの大きなソートされたリスト(配列)にマージするという単純な問題を解決します。
    アルゴリズムは3つのポインターを維持します。1つは2つの配列のそれぞれに対応し、もう1つは最終的にソートされた配列の現在のインデックスを維持するために使用します。

我们已经到达任何阵列的末端了吗?
否:
  比较两个数组的当前元素
  将较小的元素复制到排序的数组中
  移动包含较小元素的元素的指针
是:
  复制非空数组的所有剩余元素

ここに画像の説明を挿入します

マージアルゴリズムのコードを書く

    上記のマージステップとマージソートに使用されるマージステップの明らかな違いの1つは、連続するサブ配列に対してのみマージ機能を実行することです。
    これが、配列、最初の位置、最初のサブ配列の最後のインデックス(2番目のサブ配列の最初のインデックスを計算できます)、および2番目のサブ配列の最後のインデックスのみが必要な理由です。
    私たちのタスクは、2つのサブ配列A [p ... q]とA [q + 1 ... r]をマージして、ソートされた配列A [p ... r]を作成することです。したがって、関数の入力はA、p、q、およびrです。
    マージ関数の動作原理は次のとおりです。

  1. サブ配列L←A [p…q]およびM←A [q + 1…r]のコピーを作成します。
  2. 3つのポインタi、j、およびk
    aを作成します。1から開始して、iは現在のインデックスをL
    bとして保持します。1から開始して、jは現在のインデックスをM
    cとして保持します。pから開始して、kは現在のインデックスをA [p…として保持します。 Q]。
  3. LまたはMの終わりに到達する前に、LおよびMから大きい要素を選択し、それらをA [p ... q]の正しい位置に配置します。
  4. LまたはMの要素が使い果たされたら、残りの要素を選択してA [p ... q]に入れます。

    コードでは、これは次のようになります。

// Merge two subarrays L and M into arr
void merge(int arr[], int p, int q, int r) {
    
    

    // Create L ← A[p..q] and M ← A[q+1..r]
    int n1 = q - p + 1;
    int n2 = r - q;

    int L[n1], M[n2];

    for (int i = 0; i < n1; i++)
        L[i] = arr[p + i];
    for (int j = 0; j < n2; j++)
        M[j] = arr[q + 1 + j];

    // Maintain current index of sub-arrays and main array
    int i, j, k;
    i = 0;
    j = 0;
    k = p;

    // Until we reach either end of either L or M, pick larger among
    // elements L and M and place them in the correct position at A[p..r]
    while (i < n1 && j < n2) {
    
    
        if (L[i] <= M[j]) {
    
    
            arr[k] = L[i];
            i++;
        } else {
    
    
            arr[k] = M[j];
            j++;
        }
        k++;
    }

    // When we run out of elements in either L or M,
    // pick up the remaining elements and put in A[p..r]
    while (i < n1) {
    
    
        arr[k] = L[i];
        i++;
        k++;
    }

    while (j < n2) {
    
    
        arr[k] = M[j];
        j++;
        k++;
    }
}
Merge()関数が段階的に説明されています

    この関数には多くのことが起こるので、例を見て、どのように機能するかを見てみましょう。
ここに画像の説明を挿入します
    配列A [0…5]には、2つのソートされたサブ配列A [0…3]とA [4…5]が含まれています。マージ関数が2つの配列をマージする方法を見てみましょう。

void merge(int arr[], int p, int q, int r) {
    
    
// Here, p = 0, q = 4, r = 6 (size of array)

    ステップ1:ソートするサブアレイのコピーを作成する

    // Create L ← A[p..q] and M ← A[q+1..r]
    int n1 = q - p + 1 = 3 - 0 + 1 = 4;
    int n2 = r - q = 5 - 3 = 2;

    int L[4], M[2];

    for (int i = 0; i < 4; i++)
        L[i] = arr[p + i];
        // L[0,1,2,3] = A[0,1,2,3] = [1,5,10,12]

    for (int j = 0; j < 2; j++)
        M[j] = arr[q + 1 + j];
        // M[0,1,2,3] = A[4,5] = [6,9]

ここに画像の説明を挿入します
    ステップ2:サブアレイとメインアレイの現在のインデックスを維持する

    int i, j, k;
    i = 0; 
    j = 0; 
    k = p; 

ここに画像の説明を挿入します
    ステップ3:LまたはMの終わりに到達する前に、要素LおよびMから大きい方の要素を選択し、それらをA [p ... r]の正しい位置に配置します。

    while (i < n1 && j < n2) {
    
     
        if (L[i] <= M[j]) {
    
     
            arr[k] = L[i]; i++; 
        } 
        else {
    
     
            arr[k] = M[j]; 
            j++; 
        } 
        k++; 
    }

ここに画像の説明を挿入します
    ステップ4:LまたはMの要素が使い果たされたら、残りの要素を選択して[p ... r]に入力します。

    // We exited the earlier loop because j < n2 doesn't hold
    while (i < n1)
    {
    
    
        arr[k] = L[i];
        i++;
        k++;
    }

ここに画像の説明を挿入します

    // We exited the earlier loop because i < n1 doesn't hold  
    while (j < n2)
    {
    
    
        arr[k] = M[j];
        j++;
        k++;
    }
}

ここに画像の説明を挿入します
    Mの値がLより大きい場合は、この手順が必要です。
    マージ関数の最後に、サブ配列A [p ... r]がソートされます。

Cの例
// Merge sort in C

#include <stdio.h>

// Merge two subarrays L and M into arr
void merge(int arr[], int p, int q, int r) {
    
    

  // Create L ← A[p..q] and M ← A[q+1..r]
  int n1 = q - p + 1;
  int n2 = r - q;

  int L[n1], M[n2];

  for (int i = 0; i < n1; i++)
    L[i] = arr[p + i];
  for (int j = 0; j < n2; j++)
    M[j] = arr[q + 1 + j];

  // Maintain current index of sub-arrays and main array
  int i, j, k;
  i = 0;
  j = 0;
  k = p;

  // Until we reach either end of either L or M, pick larger among
  // elements L and M and place them in the correct position at A[p..r]
  while (i < n1 && j < n2) {
    
    
    if (L[i] <= M[j]) {
    
    
      arr[k] = L[i];
      i++;
    } else {
    
    
      arr[k] = M[j];
      j++;
    }
    k++;
  }

  // When we run out of elements in either L or M,
  // pick up the remaining elements and put in A[p..r]
  while (i < n1) {
    
    
    arr[k] = L[i];
    i++;
    k++;
  }

  while (j < n2) {
    
    
    arr[k] = M[j];
    j++;
    k++;
  }
}

// Divide the array into two subarrays, sort them and merge them
void mergeSort(int arr[], int l, int r) {
    
    
  if (l < r) {
    
    

    // m is the point where the array is divided into two subarrays
    int m = l + (r - l) / 2;

    mergeSort(arr, l, m);
    mergeSort(arr, m + 1, r);

    // Merge the sorted subarrays
    merge(arr, l, m, r);
  }
}

// Print the array
void printArray(int arr[], int size) {
    
    
  for (int i = 0; i < size; i++)
    printf("%d ", arr[i]);
  printf("\n");
}

// Driver program
int main() {
    
    
  int arr[] = {
    
    6, 5, 12, 10, 9, 1};
  int size = sizeof(arr) / sizeof(arr[0]);

  mergeSort(arr, 0, size - 1);

  printf("Sorted array: \n");
  printArray(arr, size);
}
マージソートの複雑さ

    時間計算量
    ベストケースの複雑さ:O(n * log n)
    ワーストケースの複雑さ:O(n * log n)
    平均ケースの複雑さ:O(n * log n)
    スペースの複雑さ
    マージソートのスペースの複雑さはO(n)です。

マージソートアプリケーション
  • カウントダウンの問題
  • 外部分類
  • Eコマースアプリケーション
参照文書

[1]パレワラボPvt。Ltd.マージソートアルゴリズム[EB / OL] .https://www.programiz.com/dsa/merge-sort,2020-01-01。

おすすめ

転載: blog.csdn.net/zsx0728/article/details/114823007