归并排序的核心思想是将两个已经排序的序列合并成一个序列,那如何得到两个已经排序的序列呢?我们知道, 如果一个序列只有一个元素,那该序列是已经排序的,这样我们就可以利用分治的思想,将未排序的序列划分成更小的序列,只到我们可以很方便的对小序列进行排序(比如划分到序列只有一个元素, 或者序列很小可以方便的使用其它排序算法进行排序),然后再将小序列逐次合并,得到最后的排序结果。
实现:
1: /*
2: * @brief 将两个已排序的序列 in[l...m]和in[m+1...r]合并,放入out中
3: * num 为计算逆序对所用
4: */
5: int num = 0;
6: void merge(int in[], int out[], int l, int m, int r)
7: {
8: int i = l;
9: int k = m + 1;
10:
11: while (l <= m && k <= r) {
12: if (in[l] <= in[k]) {
13: out[i++] = in[l++];
14: } else {
15: out[i++] = in[k++];
16: /* 因为此时in[l...m]已经排序,如果in[l] 与 in[k] 逆序,
17: 则in[l+1], in[l+2]...in[m] 都与in[k]逆序, 共 m-l+1 对*/
18: num += m - l + 1; /* calculate the inversion number */
19: }
20: }
21: while (l <= m) {
22: out[i++] = in[l++];
23: }
24: while (k <= r) {
25: out[i++] = in[k++];
26: }
27: }
28:
29: /*
30: * @brief 递归将序列划分为只有一个元素的子序列, 然后逐次对子序列进行合并
31: */
32: void m_sort(int in[], int out[], int l, int r)
33: {
34: /* 仅有一个元素, 已排序, 递归结束 */
35: if (l >= r) {
36: return;
37: }
38:
39: /* 计算 l 和 r 的中间值, 防止溢出 */
40: int m = (l & r) + ((l ^ r) >> 1);
41: /* note that in and out are swapped */
42: m_sort(out, in, l, m);
43: m_sort(out, in, m + 1, r);
44:
45: merge(in, out, l, m, r);
46: }
47:
48: /*
49: * @brief merge sort
50: * 统一申请空间, 避免反复申请释放
51: */
52: int merge_sort(int a[], int n)
53: {
54: int *b = (int *)malloc(n * sizeof(int));
55: if (b) {
56: memcpy(b, a, n * sizeof(int));
57: m_sort(b, a, 0, n - 1);
58: free(b);
59: return 0;
60: }
61:
62: return -1;
63: }