归并排序
过程:一个数组,分成两个序列,通过递归(排序的方式)将左部分的值排好,再将右部分的值排好,左右两边排好后,再将两边的数据拿出来统一排好,即将两个有序数列合并为一个有序数列;
图画演示:
1、分散(从整到零)
将原始序列一刀切开,划分成两个序列。然后每个序列继续切开,又划分成两个更小的序列。
这样一层层地划分,可以得到一颗划分的树,树的叶子节点就是原始序列的每个元素了。
2、合并(从零到整)
从树的叶子节点开始沿着枝干往上合并,序列数越来越少,每个序列的长度越来越大,最终剩下一个序列,这个序列即为所求。
这时候注意,每次合并时,输入的是两个有序数列,输出的是一个合并之后的有序数列。
代码演示:
import java.util.Arrays;
public class 归并 {
public static void mergeSort(int[] arr) {
if(arr==null || arr.length<2) {
return;
}
sortProcess(arr, 0, arr.length-1);;
}
public static void sortProcess(int[] arr, int L,int R) {
if(L==R)
return;
int mid = L + ((R - L)>> 1); //L和R的中点
sortProcess(arr,L,mid); //arr的左部分(有序)
sortProcess(arr, mid + 1, R); //arr的右部分(有序)
merge(arr, L, mid, R); //左右有序合并
}
public static void merge(int[]arr, int L, int mid, int R) {
int[] help = new int[R-L+1];
int i = 0;
int p1 = L;
int p2 = mid + 1;
while(p1 <= mid && p2<= R) {
help[i++] = arr[p1]<arr[p2] ? arr[p1++] : arr[p2++];
}
// 两个必有且只有一个越界
while(p1 <= mid)
help[i++] = arr[p1++];
while(p2 <= R)
help[i++] = arr[p2++];
for(i = 0; i< help.length;i++)
arr[L+i] = help[i];
}
public static void main(String[] args) {
int[] arr = {1,9,8,7,5,25,45,6,2,3,0};
mergeSort(arr);
System.out.println(Arrays.toString(arr));
}
}
3、复杂度
1)、时间复杂度
由“分散”和“合并”两部分组成。
“分散”:最后分成一个个的单一元素,因此复杂度为 O(n)。
“合并”:由于每次进行两两合并,因此合并的次数为 O(logn),而每次合并的复杂度为 O(n),因此整体合并的复杂度为 O(nlogn)。
因此,整个算法的时间复杂度为 O(nlogn)。
2)、空间复杂度
归并的空间复杂度就是那个临时的数组和递归时压入栈的数据占用的空间:n + logn;所以空间复杂度为 O(n)。