排序算法之归并排序MergeSort

排序算法之归并排序


归并排序的主要思想为:分治法
即将问题分解为本质相同的若干个分问题,通过对分问题的求解,达到对总问题求解的目的。中间会用到编程中的一个重要思想—递归思想。


现在假设给定一个无序的长度为n的数组

  • 我们可以取数组的中间值mid
  • 然后我们可以得到两个数组,那么相似的,我们也可以把对这两个数组排序的问题看做同对原数组排序一样的分问题。
  • 假定我们已经利用递归思想对上述两个数组完成了排序,那么我们只需要合并两个数组便可以完成对原数组的排序了。
  • 接着,我们可以把这两个数组理解为整理好的两堆书,为了合并为一堆有序的书,我们把两堆书都有序的摆放。
  • 一次比较放在两堆书上最上边的那本书,将排序靠前的书拿出来。
  • 重复上一步骤直到其中一堆书被拿完,剩下的书再依次的拿出来。(在实际操作中,我们也可以采用另一种思路,即:在两堆书的最下边放上一本标记书(我们称为信号量),所有其他的书与标记书比较时都排在前面。这样我们便不必统计什么时候其中的一堆书被拿完了,只需考虑从两堆书中拿出n本书即可完成排序,因为最后肯定会剩下两本标记书)

具体过程见下图:
MergeSort


代码展示:
cpp 版

#include <iostream>
using namespace std;
const int INF=0x3f3f3f3f;	//定义一个“大数”
// 排序的部分开始为head,结尾为tail,中间值为mid
// 用来合并两组数的Merge函数
void merge(int a[], int head, int mid, int tail) {
    int n1 = mid - head + 2;
    int n2 = tail - mid + 1;
    // 将两部分取出来存在新数组中
    int B[n1];
    int C[n2];
    for (int i=0; i<n1-1; i++) {
        B[i] = a[i + head];
    }
    for (int i=0; i<n2-1; i++) {
        C[i] = a[i + 1 + mid];
    }
    // 存储信号量
    B[n1 - 1] = INF;
    C[n2 - 1] = INF;
    int i = 0, j = 0;
    for (int k=head; k!=tail+1; k++) {
        if (B[i] <= C[j]) {
            a[k] = B[i++];
        }
        else {
            a[k] = C[j++];
        }
    }
}
// 排序函数mergeSort
void mergeSort(int a[], int head, int tail) {
    if (head < tail) {
        // 取中间值
        int mid = (head + tail) / 2;
        // 递归分解head到mid的数据
        mergeSort(a, head, mid);
        // 递归分解mid+1到end的数据
        mergeSort(a, mid + 1, tail);
        // 合并两组排好序的数据
        merge(a, head, mid, tail);
    }
}
int main() {
    int a[] = {1, 30, 20, 34, 78, 99, 40, 2, 7, 16};
    // 注意index不要越界
    mergeSort(a, 0, 9);
	int i = 0;
	for (i=0; i<10; i++) {
        cout << a[i] << " ";
    }
	cout << endl;
    return 0;
}

output:
1 2 7 16 20 30 34 40 78 99 

java 版

// 定义MergeSort类
public class MergeSort {
    // 由递归思想我们认为,我们要对从p到r的数组片段进行排序
    // p即为head,r即为tail,q即为mid
    // 用来合并两组数的Merge函数
    public static void merge(int[] a, int p, int q, int r) {
        int n1 = q - p + 2;
        int n2 = r - q + 1;
        // 将两组数分别另存起来
        int[] B = new int[n1];
        int[] C = new int[n2];
        // 这里的a为原数组的地址,而我们只操作原数组上的一部分
        // 即从p到q,从q+1到r,注意index的值
        for (int i=0; i<n1-1; i++) {
            B[i] = a[i + p];
        }
        for (int i=0; i<n2-1; i++) {
            C[i] = a[i + q + 1];
        }
        // 放入信号量
        B[n1 - 1] = (int)Double.POSITIVE_INFINITY;
        C[n2 - 1] = (int)Double.POSITIVE_INFINITY;
        int i = 0, j = 0;
        for (int k=p; k!=r+1; k++) {
            if (B[i] <= C[j]) {
                a[k] = B[i];
                i++;
            }
            else {
                a[k] = C[j];
                j++;
            }
        }
    }
    // 排序函数mergeSort
    public static void mergeSort(int[] a, int p, int r) {
        if (p < r) {
            // 取中间值
            int q = (p + r) / 2;
            // 递归分解p到q-1的数据
            mergeSort(a, p, q);
            // 递归分解q到r的数据
            mergeSort(a, q + 1, r);
            // 合并两组排好序的数据
            merge(a, p, q, r);
        }
    }
    public static void main(String[] args) {
        int[] a = {1, 30, 20, 34, 78, 99, 40, 2, 7, 16};
        // 注意index不要越界
        mergeSort(a, 0, a.length - 1);
        for (int i=0; i<a.length; i++) {
            System.out.printf("%d ", a[i]);
        }
    }
}
output
1 2 7 16 20 30 34 40 78 99 

最后推荐给大家一个可以可视化数据结构与算法的网站:VisuAlgo
如果你也喜欢这篇文章,请点个赞哦~

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值