マージソートアルゴリズム - Java、C、およびPythonの実装
マージソートは、最も効率的なソートアルゴリズムの一つです。これは、リストを複数のサブリストに分割し、各サブリストが単一の要素から成るまで分解するという考え方に基づいた分割統治の原則に基づいて機能し、それらのサブリストを結合して整列されたリストを得る方法で行われます。
マージソートの作業ルール
分割統治の概念は三つのステップを含みます:
- 問題をいくつかのサブプロブレムに分ける。
- サブ問題を解決します。アイデアは問題を原子的なサブ問題に分割し、実際にそれらを解決することです。
- サブ問題の解決策を結合して、実際の問題の解決策を見つけます。
つまり、マージソートの作業ルールは以下のステップを含みます:
- 未ソートの配列を単一要素を含むサブ配列に分割します。
- 隣接する2つの単一要素配列のペアを取り、それらをマージして2要素の配列を形成します。
- 単一のソートされた配列が得られるまでそのプロセスを繰り返してください。
サイズ‘N’の配列は、各々‘N/2’のサイズの2つの部分に分割されます。それから、1つの要素に達するまで、さらなる分割が行われます。ここでの基本ケースは、1つの単一要素に達することです。基本ケースに達した際に、左部分と右部分をマージし、最終的にソートされた配列を得ます。マージソートは、配列を複数のサブ配列に繰り返し分解し、各サブ配列が単一の要素となるまで分解し、その後、ソートされた配列が得られるようにサブ配列をマージします。
マージソートアルゴリズムのフロー
配列={70,50,30,10,20,40,60}
配列を左側と右側の2つの部分に繰り返し分割します。分割は中央の要素から行われます。単一の要素に達するまで分割し、その後、整列された配列を形成するためにそれらを結合し始めます。
マージソートの実装
私たちはJava、C、Pythonでマージソートアルゴリズムを実装します。
1. Javaの実装
package com.journaldev.ds;
public class MergeSort {
public static void main(String[] args) {
int[] arr = { 70, 50, 30, 10, 20, 40, 60 };
int[] merged = mergeSort(arr, 0, arr.length - 1);
for (int val : merged) {
System.out.print(val + " ");
}
}
public static int[] mergeTwoSortedArrays(int[] one, int[] two) {
int[] sorted = new int[one.length + two.length];
int i = 0;
int j = 0;
int k = 0;
while (i < one.length && j < two.length) {
if (one[i] < two[j]) {
sorted[k] = one[i];
k++;
i++;
} else {
sorted[k] = two[j];
k++;
j++;
}
}
if (i == one.length) {
while (j < two.length) {
sorted[k] = two[j];
k++;
j++;
}
}
if (j == two.length) {
while (i < one.length) {
sorted[k] = one[i];
k++;
i++;
}
}
return sorted;
}
public static int[] mergeSort(int[] arr, int lo, int hi) {
if (lo == hi) {
int[] br = new int[1];
br[0] = arr[lo];
return br;
}
int mid = (lo + hi) / 2;
int[] fh = mergeSort(arr, lo, mid);
int[] sh = mergeSort(arr, mid + 1, hi);
int[] merged = mergeTwoSortedArrays(fh, sh);
return merged;
}
}
出力
2. C言語の実装
#include <stdio.h>
void merge(int arr[], int l, int m, int r)
{
int i, j, k;
int n1 = m - l + 1;
int n2 = r - m;
/* create temp arrays */
int L[n1], R[n2];
/* Copy data to temp arrays L[] and R[] */
for (i = 0; i < n1; i++)
L[i] = arr[l + i];
for (j = 0; j < n2; j++)
R[j] = arr[m + 1+ j];
/* Merge the temp arrays back into arr[l..r]*/
i = 0; // Initial index of first subarray
j = 0; // Initial index of second subarray
k = l; // Initial index of merged subarray
while (i < n1 && j < n2)
{
if (L[i] <= R[j])
{
arr[k] = L[i];
i++;
}
else
{
arr[k] = R[j];
j++;
}
k++;
}
/* Copy the remaining elements of L[], if there
are any */
while (i < n1)
{
arr[k] = L[i];
i++;
k++;
}
/* Copy the remaining elements of R[], if there
are any */
while (j < n2)
{
arr[k] = R[j];
j++;
k++;
}
}
/* l is for left index and r is the right index of the
sub-array of arr to be sorted */
void mergeSort(int arr[], int l, int r)
{
if (l < r)
{
// Same as (l+r)/2, but avoids overflow for
// large l and h
int m = l+(r-l)/2;
// Sort first and second halves
mergeSort(arr, l, m);
mergeSort(arr, m+1, r);
merge(arr, l, m, r);
}
}
void printArray(int A[], int size)
{
int i;
for (i=0; i < size; i++)
printf("%d ", A[i]);
printf("\n");
}
/* Driver program to test above functions */
int main()
{
int arr[] = {70, 50, 30, 10, 20, 40,60};
int arr_size = sizeof(arr)/sizeof(arr[0]);
printf("Given array is \n");
printArray(arr, arr_size);
mergeSort(arr, 0, arr_size - 1);
printf("\nSorted array is \n");
printArray(arr, arr_size);
return 0;
}
出力
3. Pythonの実装
def merge_sort(unsorted_array):
if len(unsorted_array) > 1:
mid = len(unsorted_array) // 2 # Finding the mid of the array
left = unsorted_array[:mid] # Dividing the array elements
right = unsorted_array[mid:] # into 2 halves
merge_sort(left)
merge_sort(right)
i = j = k = 0
# data to temp arrays L[] and R[]
while i < len(left) and j < len(right):
if left[i] < right[j]:
unsorted_array[k] = left[i]
i += 1
else:
unsorted_array[k] = right[j]
j += 1
k += 1
# Checking if any element was left
while i < len(left):
unsorted_array[k] = left[i]
i += 1
k += 1
while j < len(right):
unsorted_array[k] = right[j]
j += 1
k += 1
Code to print the list
def print_list(array1):
for i in range(len(array1)):
print(array1[i], end=" ")
print()
driver code to test the above code
if __name__ == '__main__':
array = [12, 11, 13, 5, 6, 7]
print("Given array is", end="\n")
print_list(array)
merge_sort(array)
print("Sorted array is: ", end="\n")
print_list(array)
出力
マージソートの時間と空間の複雑さ
1. 空間の複雑さ
補助空間: O(n) インプレースソート: いいえ アルゴリズム : 分割統治法
2. 時間計算量
マージソートは再帰的アルゴリズムであり、時間計算量は次の再帰関係式として表現できます。T(n)=2T(n/2) + O(n) 上記の再帰の解はO(nLogn)です。サイズNのリストは最大でLogn部分に分割され、すべてのサブリストを1つのリストにマージするのにO(N)の時間がかかります。このアルゴリズムの最悪の場合の実行時間はO(nLogn)です。最良の場合の時間計算量:O(n*log n)最悪の場合の時間計算量:O(n*log n)平均の場合の時間計算量:O(n*log n)マージソートの時間計算量は、3つのすべてのケース(最悪、平均、最良)でO(n*Log n)です。これは、マージソートが常に配列を2つの半分に分割し、2つの半分をマージするのに線形時間がかかるためです。さらに読む:
- マージソートのウィキペディアページ
- Javaでのバブルソート
- Javaでの挿入ソート




