归并排序(Merge Sort)是采用分治法、建立在归并操作上的一种有效、稳定的排序算法,可以分为两个阶段:
- 递归阶段:将数组分解成两个子数组,对每个子数组进行排序,直到子数组的长度为 1。
- 合并阶段:将两个已排序的子数组合并成一个已排序的数组。
归并排序的步骤如下:
- 分解:将待排序的数组分成两个子数组,每个子数组包含一半的元素。
- 递归排序:对每个子数组分别进行归并排序。
- 合并:合并两个已排序的子数组。
其中第3步详细过程如下:
- 创建一个空的临时数组,用于存储合并后的结果。
- 初始化两个指针,分别指向两个已排序的子数组的第一个元素。
- 比较两个指针指向的元素,如果第一个子数组的元素小于第二个子数组的元素,则将第一个子数组的元素放入临时数组中,并将第一个指针向后移动一位。
- 如果第一个子数组的元素大于等于第二个子数组的元素,则将第二个子数组的元素放入临时数组中,并将第二个指针向后移动一位。
- 重复步骤 3 和步骤 4,直到其中一个子数组的所有元素都被放入临时数组中。
- 将剩余的子数组的元素放入临时数组中。
- 将临时数组中的元素复制回原数组中。
动画演示
下面为各编程语言实现归并排序的方法
C语言
#include <stdio.h>
/* 合并函数(合并两个已排序的子数组) */
void Merge(int arr[], int l, int m, int r) {
int n1 = m - l + 1;
int n2 = r - m;
// 创建两个临时数组,分别存储左半部分和右半部分
int L[n1], R[n2];
// 将左半部分和右半部分分别复制到临时数组中
for (int i = 0; i < n1; i++)
L[i] = arr[l + i];
for (int j = 0; j < n2; j++)
R[j] = arr[m + 1 + j];
// 合并临时数组中的元素
int i = 0, j = 0, k = l;
while (i < n1 && j < n2) {
if (L[i] <= R[j])
arr[k++] = L[i++];
else
arr[k++] = R[j++];
}
// 如果左半部分还有剩余元素,将它们复制到数组中
while (i < n1)
arr[k++] = L[i++];
// 如果右半部分还有剩余元素,将它们复制到数组中
while (j < n2)
arr[k++] = R[j++];
}
/* 归并排序函数 */
void MergeSort(int arr[], int l, int r) {
if (l < r) {
int m = l + (r - l) / 2;
// 对左半部分进行排序
MergeSort(arr, l, m);
// 对右半部分进行排序
MergeSort(arr, m + 1, r);
// 合并左右两个部分
Merge(arr, l, m, r);
}
}
int main() {
int arr[] = {8, 45, 0, 30, 49, 16, 20, 20};
int n = sizeof(arr) / sizeof(arr[0]); // 求数组长度
printf("排序前的数组:");
for (int i = 0; i < n; i++)
printf("%d ", arr[i]);
putchar(10);
MergeSort(arr, 0, n - 1);
printf("排序后的数组:");
for (int i = 0; i < n; i++)
printf("%d ", arr[i]);
return 0;
}
C++
#include <iostream>
using namespace std;
/* 合并函数(合并两个已排序的子数组) */
void Merge(int arr[], int l, int m, int r) {
int n1 = m - l + 1;
int n2 = r - m;
// 创建两个临时数组,分别存储左半部分和右半部分
int L[n1], R[n2];
// 将左半部分和右半部分分别复制到临时数组中
for (int i = 0; i < n1; i++)
L[i] = arr[l + i];
for (int j = 0; j < n2; j++)
R[j] = arr[m + 1 + j];
// 合并临时数组中的元素
int i = 0, j = 0, k = l;
while (i < n1 && j < n2) {
if (L[i] <= R[j]) {
arr[k++] = L[i++];
} else {
arr[k++] = R[j++];
}
}
// 如果左半部分还有剩余元素,将它们复制到数组中
while (i < n1) {
arr[k++] = L[i++];
}
// 如果右半部分还有剩余元素,将它们复制到数组中
while (j < n2) {
arr[k++] = R[j++];
}
}
/* 归并排序函数 */
void MergeSort(int arr[], int l, int r) {
if (l < r) {
int m = l + (r - l) / 2;
// 对左半部分进行排序
MergeSort(arr, l, m);
// 对右半部分进行排序
MergeSort(arr, m + 1, r);
// 合并左右两个部分
Merge(arr, l, m, r);
}
}
int main() {
int arr[] = {8, 45, 0, 30, 49, 16, 20, 20};
int n = sizeof(arr) / sizeof(arr[0]);// 求数组长度
cout << "排序前的数组:";
for (int i = 0; i < n; i++)
cout << arr[i] << " ";
MergeSort(arr, 0, n - 1);
cout << endl << "排序后的数组:";
for (int i = 0; i < n; i++)
cout << arr[i] << " ";
return 0;
}
Python
''' 归并排序函数 '''
def MergeSort(arr):
# 如果数组长度为1则直接输出
if len(arr) <= 1:
return arr
# 否则将数组对半分为左右两部分
else:
mid = len(arr) // 2
left = MergeSort(arr[:mid])
right = MergeSort(arr[mid:])
return Merge(left, right)
''' 合并函数(合并两个已排序的子数组) '''
def Merge(left, right):
merged = []
i, j = 0, 0
# 合并临时数组中的元素
while i < len(left) and j < len(right):
if left[i] <= right[j]:
merged.append(left[i])
i += 1
else:
merged.append(right[j])
j += 1
merged.extend(left[i:])
merged.extend(right[j:])
return merged
arr = [8, 45, 0, 30, 49, 16, 20, 20]
print("排序前的数组:", ' '.join(map(str, arr)))
arr = MergeSort(arr)
print("排序后的数组:", ' '.join(map(str, arr)))
Java
public class Merge_Sort {
/* 合并函数(合并两个已排序的子数组) */
public static void Merge(int[] arr, int l, int m, int r) {
int n1 = m - l + 1;
int n2 = r - m;
// 创建两个临时数组,分别存储左半部分和右半部分
int[] L = new int[n1];
int[] R = new int[n2];
// 将左半部分和右半部分分别复制到临时数组中
for (int i = 0; i < n1; i++)
L[i] = arr[l + i];
for (int j = 0; j < n2; j++)
R[j] = arr[m + 1 + j];
// 合并临时数组中的元素
int i = 0, j = 0, k = l;
while (i < n1 && j < n2) {
if (L[i] <= R[j])
arr[k++] = L[i++];
else
arr[k++] = R[j++];
}
// 如果左半部分还有剩余元素,将它们复制到数组中
while (i < n1)
arr[k++] = L[i++];
// 如果右半部分还有剩余元素,将它们复制到数组中
while (j < n2)
arr[k++] = R[j++];
}
/* 归并排序函数 */
public static void MergeSort(int[] arr, int l, int r) {
if (l < r) {
int m = l + (r - l) / 2;
// 对左半部分进行排序
MergeSort(arr, l, m);
// 对右半部分进行排序
MergeSort(arr, m + 1, r);
// 合并左右两个部分
Merge(arr, l, m, r);
}
}
public static void main(String[] args) {
int[] arr = {8, 45, 0, 30, 49, 16, 20, 20};
System.out.print("排序前的数组为:");
for (int i = 0; i < arr.length; i++)
System.out.print(arr[i] + " ");
System.out.println();
MergeSort(arr, 0, arr.length - 1);
System.out.print("排序后的数组为:");
for (int i = 0; i < arr.length; i++)
System.out.print(arr[i] + " ");
}
}