排序算法之归并排序

归并排序的主要思路分为两个部分:1.分治,2.归并。算法的平均时间复杂度为O(nlogn),需要辅助空间O(n)。

1.分治需要将数组分为两个部分,针对每个部分进行归并排序,待两个子数组都有序后(归并的条件),进行归并。

2.归并的函数需要三个数组位置索引,数组的起始位置L,右子数组的开始位置M(作为左子数组和右子数组的分界线),数组的结束位置R。首先需要将原数组根据三个索引拆分成左子数组和右子数组,从左子数组、右子数组、原数组的第一个位置开始,若左子数组指向元素小于右子数组指向元素,则将左子数组的元素赋值给原数组,左子数组的索引和原数组的索引分别后移1位。否则,将右子数组的索引和原数组的索引后移一位。一旦出现某个子数组越界,则证明该子数组中的元素已经全部填充进原数组中了。只需将另外一个子数组的剩余元素填入原数组中即可,此时整个数组即为有序了。

/**
 * 归并排序:需要辅助空间,O(n),平均时间复杂度O(nlogn)
 * 主要思想:1.分治 2.归并
 *
 */
public class Solution {
	
	/**
	 * 归并,L,M,R代表待归并的范围,将数组分为两个部分,并且此时假设L-M-1,M-R是排好序的
	 * 即归并的过程必须保证数组两边是有序的
	 * @param arr 数组
	 * @param L   数组的起始位置
	 * @param M   数组的中间位置,不一定是中位数
	 * @param R   数组的结束位置
	 * 
	 */
	public void merge(int[] arr, int L, int M, int R) {
		//将原数组拆分成两个子数组,需要额外申请内存空间
		//1.确定左、右子数组的长度
		int leftLength = M - L;
		int rightLength = R - M + 1;
		
		//创建两个子数组
		int[] leftArr = new int[leftLength];
		int[] rightArr = new int[rightLength];
		
		//从原数组中为子数组赋值
		for (int i = L; i < M; i++) {
			leftArr[i - L] = arr[i];
		}
		
		for (int i = M; i <= R; i++) {
			rightArr[i - M] = arr[i];
		}
		
		//利用这两个子数组对原数组元素进行调整,形成排序的数组
		//是对两个已经排好序的子数组的合并成一个有序数组的过程
		int i = 0;//指向左子数组的第一个元素
		int j = 0;//指向右子数组的第一个元素
		int k = L;//指向原数组的起始位置
		
		//在保证子数组不越界的情况下
		while (i < leftLength && j < rightLength) {
			if (leftArr[i] < rightArr[j]) {
				//如果左子数组的元素值较小,则赋值到原数组中
				arr[k] = leftArr[i];
				i++;
				k++;
			} else {
				//如果右子数组的元素值较小,则赋值到原数组中
				arr[k] = rightArr[j];
				j++;
				k++;
			}
		}
		
		//跳出循环时
		while (i < leftLength) {
			arr[k] = leftArr[i];
			i++;
			k++;
		}
		
		while (j < rightLength) {
			arr[k] = rightArr[j];
			j++;
			k++;
		}
		
	}
	
	
	/**
	 * 归并排序,先进行分治,在排序
	 * @param arr  数组
	 * @param L    数组的起始位置
	 * @param R    数组的结束位置
	 */
	public void merge_Sort(int[] arr, int L, int R) {
		
		if (arr == null || L < 0 || R > arr.length - 1) {
			return;
		}
		
		//递归的结束条件
		if(L == R) {
			return;
		}
		
		int M = (L + R) / 2;
		//递归地对前半部分进行归并排序
		merge_Sort(arr, L, M);
		//递归地对后半部分进行归并排序
		merge_Sort(arr, M + 1, R);
		//将已经排好序的两部分合并起来
		merge(arr, L, M + 1, R);
	}
	
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值