归并排序

痞子三分冷 提交于 2020-03-01 03:05:47

描述: 归并排序就是将两个或两个以上有序表合并成一个有序表的过程。将两个有序表合并成一个有序表的过程称为2-路归并,下面以2-路归并为例其排序过程是:

  • 假设初始序列有n个元素,则可看成n个长度为1有序子序列,然后两两归并,得到n/2\lceil n/2 \rceil(向上取整,大于等于n/2的最小整数)个长度为2或1(奇数个元素剩个元素单独成列)的有序子序列;再两两归并,如此重复,直到得到一个长度为n的有序序列为止。
  • 其中两个有序子序列合并成一个序列的过程为:初始两子序列下标都指向首元素,每次都比较两下标元素,小的放入辅助数组并下标后移一位,直至其中一个数组全部完成比较,将另一个数组剩下的元素全部放进辅助数组。

java代码

import java.util.Arrays;

public class MergeSort {
	
	// 外部调用接口
	public static void mergeSort(int[] arr) {
		// 避免递归过程中频繁开辟空间,开始建一个长度的等于原数组长的临时数组
		int[] temp = new int[arr.length];
		sort(arr, 0, arr.length - 1, temp);
	}
	
	private static void sort(int[] arr, int left, int right, int[] temp) {
		// 递归出口left=right,即子序列长度为1
		if (left < right) {
			int mid = (left + right) / 2;
			sort(arr, left, mid, temp); 	// 对左子序列递归调用并归完成排序
			sort(arr, mid + 1, right, temp); 	// 对右子序列递归调用并归完成排序
			merge(arr, left, mid, right, temp); 	// 将两个有序子序列合并
		}
	}

	// 将传入数组arr一分为二排序好后返回给原数组位置
	private static void merge(int[] arr, int left, int mid, int right, int[] temp) {
		int i = left;
		int j = mid + 1;
		int t = 0;
		while (i <= mid && j <= right)
			temp[t++] = arr[i] < arr[j] ? arr[i++] : arr[j++];
		while (i <= mid)
			temp[t++] = arr[i++];
		while (j <= right)
			temp[t++] = arr[j++];

		t = 0;
		while (left <= right)
			arr[left++] = temp[t++];
	}

	
	// 测试
	public static void main(String[] args) {
		int[] arr = new int[1000];
		for (int i = 0; i < 1000; i++)
			arr[i] = (int) (Math.random() * 999 + 1);
		mergeSort(arr);
		System.out.println(Arrays.toString(arr));
	}

}

算法分析

  • 时间复杂度O(nlog2n)Ο(nlog_2{n}),n个元素需进行log2n\lceil log_2{n} \rceil趟归并排序,每一趟归并,比较次数不超过n,移动次数2n,因此归并排序时间复杂度O(nlog2n)Ο(nlog_2{n})
  • 空间复杂度O(n)Ο(n),只用到了和原数组一样长的临时数组。
  • 稳定性取决于第28行三元表达式,就上面代码来说排序不稳定,将“<”换成“<=”后稳定,因为值相等时会将左边子序列元素放入辅助数组前面。
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!