1、归并排序的介绍
百度百科:归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
2、归并排序的特点:
归并排序的工作原理如下:
- 第一步:申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
- 第二步:设定两个指针,最初位置分别为两个已经排序序列的起始位置
- 第三步:比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
- 重复步骤3直到某一指针超出序列尾
- 将另一序列剩下的所有元素直接复制到合并序列尾
图示:
3、归并排序的主要性能分析:
(1)稳定性
归并排序是一种稳定的排序。
(2)存储结构要求
可用顺序存储结构。也可在链表上实现。
(3)时间复杂度
对长度为n的文件,需进行logN趟二路归并,每趟归并的时间为O(n),故其时间复杂度无论是在最好情况下还是在最坏情况下均是O(nlogn)。
(4)空间复杂度
需要一个辅助向量来暂存两有序子文件归并的结果,故其辅助空间复杂度为O(n),显然它不是就地排序。
注意:
若用单链表做存储结构,很容易给出就地的归并排序
4、归并排序的代码实现
1 package com.baozi.paixu; 2 3 import java.util.Arrays; 4 5 /** 6 * 合并排序:合并排序,顾名思义,就是通过将两个有序的序列合并为一个大的有序的序列的方式来实现排序。合并排序 7 * 是一种典型的分治算法:首先将序列分为两部分,然后对每一部分进行循环递归的排序,然后逐个将结果进行合并。 8 * 9 * @author BaoZi 10 * @create 2019-05-15-18:16 11 */ 12 public class MergeSort { 13 public static void main(String[] args) { 14 final int MAX =15; 15 int[] nums = new int[MAX]; 16 System.out.println("...............使用的是归并排序算法..............."); 17 for (int i = 0; i < MAX; i++) { 18 nums[MAX - i - 1] = i + 1; 19 } 20 System.out.println("排序之前的数组为..............."); 21 System.out.println(Arrays.toString(nums)); 22 System.out.println("排序之后的数组为..............."); 23 //使用归并排序算法进行排序: 24 MergeSort.mergeSort(nums); 25 System.out.println(Arrays.toString(nums)); 26 } 27 28 public static void mergeSort(int[] nums) { 29 //temp数组是一个临时数组 30 int[] temp = new int[nums.length]; 31 sort(nums, 0, nums.length - 1, temp); 32 } 33 34 private static void sort(int[] nums, int left, int right, int[] temp) { 35 if (left < right) { 36 int mid = (left + right) / 2; 37 //左边归并排序,使得左子序列有序 38 sort(nums, left, mid, temp); 39 //右边归并排序,使得右子序列有序 40 sort(nums, mid + 1, right, temp); 41 //将两个有序子数组合并操作 42 merge(nums, left, mid, right, temp); 43 } 44 } 45 //将nums[left...mid]和nums[mid+1....right]两部分进行归并 46 private static void merge(int[] nums, int left, int mid, int right, int[] temp) { 47 48 //左序列开始指针 49 int i = left; 50 //右序列开始指针 51 int j = mid + 1; 52 //临时数组指针 53 int t = 0; 54 //while循环将nums[left...mid]和nums[mid+1....right]中[left...mid]部分的元素或者 55 // nums[mid+1....right]部分的元素逐一存入temp数组中 56 while (i <= mid && j <= right) { 57 if (nums[i] <= nums[j]) { 58 temp[t++] = nums[i++]; 59 } else { 60 temp[t++] = nums[j++]; 61 } 62 } 63 //while循环结束可能是nums[left...mid]中的元素还有剩余,这种情况下需要单独存入临时数组temp中 64 //将左边剩余元素填充进temp中 65 while (i <= mid) { 66 temp[t++] = nums[i++]; 67 } 68 //while循环结束可能是nums[mid+1....right]中的元素还有剩余,这种情况下需要单独存入临时数组temp中 69 //将右序列剩余元素填充进temp中 70 while (j <= right) { 71 temp[t++] = nums[j++]; 72 } 73 //重新赋值t为0,然后把临时数组temp中的元素复制到原数组nums中 74 t = 0; 75 //nums[left...mid]和nums[mid+1....right]合并之后存入了temp数组中, 76 // 现在需要将temp中的元素全部拷贝到原数组中 77 while (left <= right) { 78 nums[left++] = temp[t++]; 79 } 80 } 81 }