《算法_第四版》(四)归并排序

本文介绍了归并排序的时间复杂度和空间复杂度,并详细讲解了自顶向下和自底向上的实现思路。重点讨论了自顶向下的归并排序,特别是merge过程中的外排思想,通过比较和合并两个数组实现排序。同时提供了简化后的外排代码示例。

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

1、归并排序

时间复杂度O(N*logN),额外空间复杂度O(N)(具体分析过程请看:递归相关算法的时间复杂度分析(master公式引入)

归并排序又分为自顶向下自底向上两种思路,这里着重说一下自顶向下

1.1 自顶向下

最主要的是这个merge的外排思想,怎么将两个数组合并起来并且排好序(其实下面代码中并不需要递归,直接 merge(arr, lo, mid, hi);就可以了,但是递归后将数组分为更小的组合然后再mergr效率会更高,这也是归并排序效率比前面几个排序算法高的原因。

外排merge的代码,我们简化后看一下,其实就是将两个数组(无论有没有序,就算没有序,我们用判断依然可以排序)来一个一个数进行比较,这里用两个指针指针两个数组的第一个数(也就是 i 和 j),,加上判断语句,这样就遍历了两个数组(注,我这里只是遍历),然后加上我们的辅助数组等操作,来达到排序的目的(在一些其他题,如小和问题、逆序问题,都用到了这个外排的思想)

最重要的思路就是用外排的思想来遍历两个数组,然后我们可以在遍历的过程中做其他的操作

下面简化后的外排代码:遍历两个数组

private void merge(int[] arr, int lo, int mid, int hi) {

		int i = lo;
		int j = mid + 1;

		for (int k = lo; k <= hi; k++) {
			arrSup[k] = arr[k];
		}

		for (int k = lo; k <= hi; k++) {
			if (i > mid) {                      //左半边用尽,用右半边元素
				j++;
			} else if (j > hi) {				//右半边用尽,用左半边元素					
				i++;
			} else if (arrSup[i] > arrSup[j]) { //如果左边最小值大于最右边,先用右半边
				j++;
			} else {							//用完再用左半边	
				i++;
			}
		}

	}

最终的自顶向下的归并排序代码:

package cn.nupt.sort;

/**
 * @Description: 归并排序(自顶向下)
 *
 * @author PizAn
 * @date 2019年1月19日 下午9:03:31
 * 
 */
public class MergeSort {

	private int[] arrSup; // 归并排序所需的辅助数组

	public void mergeSort(int[] arr) {

		arrSup = new int[arr.length]; // 对辅助数组分配空间

		sort(arr, 0, arr.length - 1);
		show(arr); // 遍历

	}

	private void sort(int[] arr, int lo, int hi) {

		if (lo >= hi)
			return;

		int mid = (lo + hi) / 2;    
		
	
		sort(arr, lo, mid);         
		sort(arr, mid + 1, hi);     

		merge(arr, lo, mid, hi);

	}

	
	//融合两个已经排序过的数组
	private void merge(int[] arr, int lo, int mid, int hi) {

		int i = lo;
		int j = mid + 1;

		for (int k = lo; k <= hi; k++) {
			arrSup[k] = arr[k];
		}

		for (int k = lo; k <= hi; k++) {
			if (i > mid) {                      //左半边用尽,用右半边元素
				arr[k] = arrSup[j++];
			} else if (j > hi) {				//右半边用尽,用左半边元素					
				arr[k] = arrSup[i++];
			} else if (arrSup[i] > arrSup[j]) { //如果左边最小值大于最右边,先用右半边
				arr[k] = arrSup[j++];
			} else {							//用完再用左半边	
				arr[k] = arrSup[i++];
			}
		}

	}

	// 遍历的实现
	private void show(int[] arr) {
		for (int i = 0; i < arr.length; i++) {
			System.out.println(arr[i]);
		}
	}

}

1.2 自底向上
package cn.nupt.sort;

/**
 * @Description: 归并排序(自底向上)
 *
 * @author PizAn
 * @date 2019年1月20日 上午9:02:05
 * 
 */
public class MergeSort {

	private int[] arrSup; // 归并排序所需的辅助数组

	public void mergeSort(int[] arr) {
		int num = arr.length;

		arrSup = new int[num]; // 对辅助数组分配空间

		for (int sz = 1; sz < num; sz = 2 * sz) {
			for (int lo = 0; lo < num - sz; lo += 2 * sz) {
				merge(arr, lo, lo + sz - 1, Math.min(lo + 2 * sz - 1, num - 1));

			}

		}
		show(arr);
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值