数据结构与:算法归并排序
2019-07-17 本文已影响0人
我爱铲屎
归并排序介绍
归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
排序过程
将一个数组分解成两个子序列,这两子序列继续分解,直到不能在分解为止;从最小的子序列开始进行归并,形成一个较大的有序子序列,再继续归并直到整个数组有序。该过程我们可以用递归来实现。排序过程如下图所示:
归并排序.png
归并操作的工作原理
将两个分别有序的子序列归并成一个新的较大有序序列,其过程如下:
1.准备一个辅助数组,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
2.设定两个指针p1和p2,最初位置分别为两个已经排序序列的起始位置
3.比较指针p1和p2所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
4.重复步骤3直到某一指针超出序列尾
5.将另一序列剩下的所有元素直接复制到合并序列尾
算法实现
public class MergeSort {
private static void mergeSort(int[] arr,int left, int right) {
if(left == right) return;
int mid = left + ((right - left) >> 1); //int mid = (left + right)/2;
mergeSort(arr,left,mid); //左侧序列分解
mergeSort(arr,mid+1,right); //右侧序列分解
merge(arr,left,mid,right); //归并
}
private static void merge(int[] arr,int left,int mid,int right) {
int[] help = new int[right - left + 1]; //准备辅助数组
//准备两个指针分别指向两个序列的开始
int p1 = left;
int p2 = mid + 1;
int i = 0;
/*
* 比较指针p1和p2所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置,
* 直到某一指针超出序列尾
* */
while(p1 <= mid && p2 <= right) {
help[i++] = (arr[p1] < arr[p2])?arr[p1++]:arr[p2++];
}
//p2指针超出序列尾,将左侧序列继续添加进辅助数组
while(p1 <= mid) {
help[i++] = arr[p1++];
}
//p1指针超出序列尾,将右侧序列继续添加进辅助数组
while(p2 <= right) {
help[i++] = arr[p2++];
}
//拷贝会原数组
for(int j = 0; j < help.length; j++) {
arr[left + j] = help[j];
}
}
public static void mergeSort(int[] arr) {
if(arr == null || arr.length < 2) return;
mergeSort(arr,0,arr.length-1);
}
//测试
public static void main(String[] args) {
int[] arr0= {10,4,6,3,8,2,5,7};
mergeSort(arr0);
for(int i=0; i<arr0.length; i++) {
System.out.print(arr0[i] + " ");
}
//2 3 4 5 6 7 8 10
System.out.println();
int[] arr1 = {10,9,8,7,6,5,4,3,2,1};
mergeSort(arr1);
for(int i=0; i<arr1.length; i++) {
System.out.print(arr1[i] + " ");
}
//1 2 3 4 5 6 7 8 9 10
}
}
复杂度
在排序中由于我们使用了辅助数组,所以额外空间复杂度为O(n);
由归并排序的递归公式:T(N) = 2T(N/2) + O(N) 可知时间复杂度为O(NlogN)
算法的复杂度与master定理:http://www.gocalf.com/blog/algorithm-complexity-and-master-theorem.html