数据结构 归并排序
Posted 王景迁
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构 归并排序相关的知识,希望对你有一定的参考价值。
归并排序采用了分治的思想(分治法将问题分(divide)成一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之)。归并指将两个或两个以上的有序表组合成一个新的有序表。假设待排序表有n个元素,看成是n个有序的子表,每个子表长度为1,然后两两归并,得到n/2个长度为2或1的有序表,继续两两归并,直到合并成一个长度为n的有序表为止,这种排序方法称为2路归并排序。
合并相邻有序子序列
将[4,5,7,8]和[1,2,3,6]两个已经有序的子序列,合并为最终序列[1,2,3,4,5,6,7,8]。
求逆序数:归并排序将数组a[l,h]分成两半a[l,mid]和a[mid+1,h]后分别进行归并排序,然后再将这两半合并起来。在合并的过程中(设l<=i<=mid,mid+1<=j<=h),当a[i]<=a[j]时,不产生逆序数;当a[i]>a[j]时,在前半部分中比a[i]大的数都比a[j]大,将a[j]放在a[i]前面的话,逆序数要加上mid+1-i。因此,可以在归并排序的合并过程中计算逆序数。
题目来源:数组中的逆序对
1 public class MergeSort {
2 // 待排序数组
3 private int[] arr;
4 // 逆序对总数
5 private int result;
6
7 // 归并两个数组
8 private void merge(int left, int mid, int right) {
9 int i = left, j = mid + 1, k = 0;
10 int[] tempArr = new int[right - left + 1];
11
12 while (i <= mid && j <= right) {
13 if (arr[i] > arr[j]) {
14 tempArr[k++] = arr[j++];
15 result += mid + 1 - i;
16 // 避免溢出
17 result %= 1000000007;
18 } else {
19 tempArr[k++] = arr[i++];
20 }
21 }
22
23 while (i <= mid) {
24 tempArr[k++] = arr[i++];
25 }
26 while (j <= right) {
27 tempArr[k++] = arr[j++];
28 }
29
30 System.arraycopy(tempArr, 0, arr, left, k);
31 }
32
33 // 归并排序
34 private void mergeSort(int left, int right) {
35 if (left < right) {
36 int mid = (left + right) >> 1;
37 mergeSort(left, mid);
38 mergeSort(mid + 1, right);
39 merge(left, mid, right);
40 }
41 }
42
43 // 获取逆序数
44 public int getResult(int[] array) {
45 if (array == null || array.length <= 1) {
46 return 0;
47 }
48
49 arr = array;
50 result = 0;
51 mergeSort(0, arr.length - 1);
52
53 return result;
54 }
55 }
测试用例:
1 import static org.junit.Assert.*;
2
3 import org.junit.Before;
4 import org.junit.Test;
5
6 public class MergeSortTest {
7 MergeSort mergeSort;
8
9 @Before
10 public void setUp() throws Exception {
11 mergeSort = new MergeSort();
12 }
13
14 @Test
15 public void test() {
16 int[] arr = {1, 2, 3, 4, 5, 6, 7, 0};
17 assertEquals(7, mergeSort.getResult(arr));
18 }
19
20 }
测试结果:
2路归并排序性能分析:
空间复杂度:2个有序表归并时最多需要n个单元的辅助空间,所以空间复杂度为O(n)。
时间复杂度:每一趟归并的时间复杂度为O(n),需要log2n趟归并,所以时间复杂度为O(nlog2n)。最好、最坏和平均时间复杂度均为O(nlog2n)。
稳定性:2个有序表归并时不会改变相同元素的相对次序,所以2路归并排序是稳定的。
Java中Arrays.sort()方法采用了一种名为TimeSort的排序算法,是归并排序的优化版本。
参考资料
《2017年数据结构联考复习指导》 P304-305
以上是关于数据结构 归并排序的主要内容,如果未能解决你的问题,请参考以下文章