Skip to content

Commit 0d91f07

Browse files
committed
feat: add MergeSort
1 parent 6cc62b3 commit 0d91f07

File tree

4 files changed

+93
-1
lines changed

4 files changed

+93
-1
lines changed

MergeSort/README.md

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
## 归并排序
2+
3+
归并排序(Merge Sort)是建立在**归并**操作上的一种排序算法。它和快速排序一样,采用了**分治法**
4+
5+
### 基本思想
6+
7+
归并的含义是将两个或两个以上的有序表组合成一个新的有序表。也就是说,从几个数据段中逐个选出最小的元素移入新数据段的末尾,使之有序。
8+
9+
那么归并排序的算法我们可以这样理解:
10+
11+
假如初始序列含有 n 个记录,则可以看成是 n 个有序的子序列,每个子序列的长度为 1。然后两两归并,得到 n/2 个长度为2或1的有序子序列;再两两归并,……,如此重复,直到得到一个长度为 n 的有序序列为止,这种排序方法称为 **二路归并排序**,下文介绍的也是这种排序方式。
12+
13+
### 动图演示
14+
15+
![](merge-sort.gif)
16+
17+
### 代码实现
18+
19+
#### C语言
20+
21+
```c
22+
/* 将 arr[L..M] 和 arr[M+1..R] 归并 */
23+
void merge(int arr[], int L, int M, int R) {
24+
int LEFT_SIZE = M - L + 1;
25+
int RIGHT_SIZE = R - M;
26+
int left[LEFT_SIZE];
27+
int right[RIGHT_SIZE];
28+
int i, j, k;
29+
// 以 M 为分割线,把原数组分成左右子数组
30+
for (i = L; i <= M; i++) left[i - L] = arr[i];
31+
for (i = M + 1; i <= R; i++) right[i - M - 1] = arr[i];
32+
// 再合并成一个有序数组(从两个序列中选出最小值依次插入)
33+
i = 0; j = 0; k = L;
34+
while (i < LEFT_SIZE && j < RIGHT_SIZE) arr[k++] = left[i] < right[j] ? left[i++] : right[j++];
35+
while (i < LEFT_SIZE) arr[k++] = left[i++];
36+
while (j < RIGHT_SIZE) arr[k++] = right[j++];
37+
}
38+
39+
void merge_sort(int arr[], int L, int R) {
40+
if (L == R) return;
41+
// 将 arr[L..R] 平分为 arr[L..M] 和 arr[M+1..R]
42+
int M = (L + R) / 2;
43+
// 分别递归地将子序列排序为有序数列
44+
merge_sort(arr, L, M);
45+
merge_sort(arr, M + 1, R);
46+
// 将两个排序后的子序列再归并到 arr
47+
merge(arr, L, M, R);
48+
}
49+
```
50+
51+
### 算法分析
52+
53+
归并排序是**稳定排序**,它和选择排序一样,性能不受输入数据的影响,但表现比选择排序更好,它的时间复杂度始终为 O(nlogn),但它需要额外的内存空间,空间复杂度为 O(n)。

MergeSort/merge-sort.gif

502 KB
Loading

MergeSort/merge_sort.c

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#include <stdio.h>
2+
3+
/* 将 arr[L..M] 和 arr[M+1..R] 归并 */
4+
void merge(int arr[], int L, int M, int R) {
5+
int LEFT_SIZE = M - L + 1;
6+
int RIGHT_SIZE = R - M;
7+
int left[LEFT_SIZE];
8+
int right[RIGHT_SIZE];
9+
int i, j, k;
10+
// 以 M 为分割线,把原数组分成左右子数组
11+
for (i = L; i <= M; i++) left[i - L] = arr[i];
12+
for (i = M + 1; i <= R; i++) right[i - M - 1] = arr[i];
13+
// 再合并成一个有序数组(从两个序列中选出最小值依次插入)
14+
i = 0; j = 0; k = L;
15+
while (i < LEFT_SIZE && j < RIGHT_SIZE) arr[k++] = left[i] < right[j] ? left[i++] : right[j++];
16+
while (i < LEFT_SIZE) arr[k++] = left[i++];
17+
while (j < RIGHT_SIZE) arr[k++] = right[j++];
18+
}
19+
20+
void merge_sort(int arr[], int L, int R) {
21+
if (L == R) return;
22+
// 将 arr[L..R] 平分为 arr[L..M] 和 arr[M+1..R]
23+
int M = (L + R) / 2;
24+
// 分别递归地将子序列排序为有序数列
25+
merge_sort(arr, L, M);
26+
merge_sort(arr, M + 1, R);
27+
// 将两个排序后的子序列再归并到 arr
28+
merge(arr, L, M, R);
29+
}
30+
31+
int main() {
32+
int arr[] = {7, 2, 6, 3, 1, 5, 8, 4};
33+
int n = sizeof(arr) / sizeof(*arr);
34+
merge_sort(arr, 0, n - 1);
35+
printf("Sort result:\n");
36+
for (int i = 0; i < n; i++)
37+
printf("%d ", arr[i]);
38+
return 0;
39+
}

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
- [希尔排序](ShellSort)
1515
- [选择排序](SelectionSort)
1616
- [堆排序](HeapSort)
17-
- 归并排序
17+
- [归并排序](MergeSort)
1818

1919
**非比较类排序**:不通过比较来决定元素间的相对次序,其时间复杂度可以突破 O(nlogn),以线性时间运行。属于非比较类的有:
2020

0 commit comments

Comments
 (0)