归并排序

归并排序核心思想:
如果要排序一个数组,先把数组从中间分成2部,然后对这2部分分别排序,再将排序好的数组进行合并。

归并排序使用的是分治思想,即将一个大问题分解成小的子问题来解决,小的子问题解决了,大问题也就解决了。

这里用递归来实现归并排序
说下写递归代码的技巧:分析出递归公式,找到终止条件,最后将递归公式翻译成代码。
递归公式:
merge_sort(l…r) = merge_sort(l…mid) + merge_sort(mid…r)
终止条件:
l>=r

解释下这个递归公式:
merge_sort(l…r)表示给下标l到r的数组排序,将这个排序问题转成了2个子问题merge_sort(l…mid)和merge_sort(mid…r),下标mid等于下标l到r的中间位置,当下标l到mid和下标mid到r这2个子数组排序好后,将2个子数组合并,这样下标l到r的数组也排序好了。

参考代码
PHP版

public function mergeSort($arr) {
	$len = count($arr);
	// 递归终止条件
	if ($len <= 1) {
	    return $arr;
	}
	
	// 取数组中间位置
	$mid = intval($len / 2);
	// 拆分数组0-mid这部分给左边left
	$left = array_slice($arr, 0, $mid);
	// 拆分数组mid-末尾这部分给右边right
	$right = array_slice($arr, $mid);
	//分治递归
	$left = $this->mergeSort($left);
	$right = $this->mergeSort($right);
	// 合并两个数组
	$arr = $this->merge($left, $right);
	
	return $arr;
}

public function merge($arr_a, $arr_b) {
	$res = [];
	
	$point_a = $point_b = 0;
	$len_a = count($arr_a) - 1;
	$len_b = count($arr_b) - 1;
	//移动数据
	while($point_a <= $len_a && $point_b <= $len_b) {
	    if ($arr_a[$point_a] <= $arr_b[$point_b]) {
	        $res[] = $arr_a[$point_a++];
	    } else {
	        $res[] = $arr_b[$point_b++];
	    }
	}
	
	//判断哪个数组有剩余数据
	if ($point_b <= $len_b) {
	    while ($point_b <= $len_b) {
	        $res[] = $arr_b[$point_b++];
	    }
	} else {
	    while ($point_a <= $len_a) {
	        $res[] = $arr_a[$point_a++];
	    }
	}
	
	return $res;
}

性能分析

  • 是稳定排序算法吗?
    结合上面的代码,可以发现,归并排序稳不稳定关键看merge()函数。
    合并过程中,如果arr_a和arr_b中有相同元素,先把arr_a中的元素放进res数组,这样保证了值相同的元素,合并前后先后顺序不变,所以是稳定排序算法

  • 时间复杂度
    最好,最好,平均情况,时间复杂度都是O(nlogn)

  • 空间复杂度
    在任意时刻,CPU中只会有一个函数在执行,所以只有一个临时内存空间在使用,临时内存空间最大也不会超过n个数据,所以空间复杂度是O(n)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值