归并排序(Merge Sort)

本文深入讲解归并排序的原理及实现过程,通过分治策略将数组不断划分直至单个元素,再逐步归并,最终得到有序数组。文章详细介绍了递归实现方式,包括递推公式、终止条件及归并操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

归并排序思想

在这里插chush入图片描述
有一个数组,

  1. 首先我们要做的就是将这个初始数组划分成两半
  2. 然后想办法把左边的数组进行排序,把右边的数组也进行排序
  3. 最后在合并起来(归并起来)

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

但是,这会有一个疑问,我怎么对左右两边的数组进行排序呢?这时候就需要重复进行上面的三个步骤,把左半部分、右半部分分别再划分成两半,直到左右两个部分只剩一个元素不能再进行划分就停止。就像下面这样:
在这里插入图片描述
这个时候左右部分只有一个元素,它们已经是排好序的了。我们只需要对他们进行归并就可以了。
在这里插入图片描述
然后就是逐层的向上归并,一直归并到整个数组的最后一层,整个数组就全部有序了。

在归并的时候,我们需要开辟一个临时数组存放每一次归并后的数据。

代码实现


递推公式:
merge_sort(l…r) = merge(merge_sort(l…mid), merge_sort(mid+1…r))

终止条件:
l >= r 不用再继续分解

merge_sort(l...r),表示需要给 lr 之间的数组进行排序。 然后我们将这整个数组的排序问题转化为左右两个子数组的排序问题。
其中下标 mid 等于 lr 的中间位置,也就是 (l+r)/2。当下标从 lmid 和从 mid+1r这两个子数组都排好序之后,我们再将两个有序的子数组合并在一起,这样下标从 lr之间的数据就也排好序了。

mergeSort(int[] arr){
	if(arr == null || arr.length < 2) return;
	mergeSort(arr,l,r);	
}

mergeSort(int[] arr,int l,int r){
	if(l >= r) return;
	int mid = l + ((r - l) >> 1);
	
	// 递归调用
	mergeSort(arr, l, mid);
	mergeSort(arr, mid + 1, r);
	merge(arr, l, mid , r);
}

merge(int[] arr, int l, int mid, int r){
	int[] tmp = new int[r - l + 1];
	int i = 0;
	int p1 = l;
	int p2 = mid + 1;
	while(p1 <= mid && p2 <= r){
		tmp[i++]  = arr[p1 <= p2] ? arr[p1] : arr[p2];
	}
	// 两个必有一个越界
	while(p1 <= mid){
		tmp[i++] = arr[p1++];
	}
	while(p2 <= r){
		tmp[i++] = arr[p2++];
	}
	for(int j = 0;j < tmp.length;j++ ){
		arr[l + 1] = tmp[j];
	}
}

在归并的操作中,我们准备了两个游标p1p2,用于表示arr[l...mid]arr[mid +1,r]的第一个位置。

比较这两个元素arr[p1]arr[p2],如果 arr[p1] <= arr[p2],我们就把 arr[p1]放入到临时数组 tmp,并且p1后移一位,否则将 arr[p2]放入到数组 tmp,p2 后移一位。

继续上面的过程,直到其中一个子数组中的所有数据都放入临时数组中,然后再把另一个数组中的数据依次加入到临时数组的末尾,这个时候,临时数组中存储的就是两个子数组合并之后的结果了。最后再把临时数组 tmp 中的数据拷贝到原数组 arr[l…r]中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值