码迷,mamicode.com
首页 > 编程语言 > 详细

数据结构 归并排序

时间:2018-01-25 00:30:53      阅读:244      评论:0      收藏:0      [点我收藏+]

标签:array   数据结构   int   detail   cti   gpo   中比   .so   阶段   

  归并排序采用了分治的思想(分治法将问题分(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个有序表归并时不会改变相同元素的相对次序,所以是一个稳定的排序方法。

  Java中Arrays.sort()方法采用了一种名为TimeSort的排序算法,是归并排序的优化版本。

  

  参考资料

  《2017年数据结构联考复习指导》 P304-305

  图解排序算法(四)之归并排序

  归并排序求逆序对

数据结构 归并排序

标签:array   数据结构   int   detail   cti   gpo   中比   .so   阶段   

原文地址:https://www.cnblogs.com/WJQ2017/p/8343714.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!