归并排序算法思想:
归并排序采用了递归的思想,假设数组中有N个数,则:
1)找到数组的中点位置mid,将数组从mid处分为两部分:左边部分和右边部分,分别在左边部分和右边部分上进行归并排序;
2)左边部分和右边部分归并排序完成后,设置一个辅助数组help,将左边部分和右边部分进行合并排序,排序结果先存放到help中,排序完成之后,将help中的结果复制回原数组。
归并排序代码:
public class MergeSort {
public void mergeSort(int[] arr) {
if (arr == null || arr.length < 2) {
return;
}
mergeSort(arr, 0, arr.length - 1);
}
public void mergeSort(int[] arr, int l, int r) {
if (l < r) {
int mid = l + ((r - l) >> 1);//找中点位置
mergeSort(arr, l, mid);
mergeSort(arr, mid + 1, r);
merge(arr,l,r,mid);//左边部分和右边部分合并
}
}
public void merge(int[] arr,int l,int r,int mid){
int[] help = new int[r - l + 1];//辅助数组
int p1 = l;
int p2 = mid + 1;
int i = 0;
while (p1 <= mid && p2 <= r) {//p1和p2都不越界的情况下
help[i++] = arr[p1] <= arr[p2] ? arr[p1++] : arr[p2++];
}
//下面的这两个while必然只会执行一个
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];
}
}
归并排序的时间复杂度解析:
master公式:
T(N) = a * T(N / b) + O(N ^ d)
其中,T(N)指的是母问题的规模是N(就是说木问题一共有N个待处理的数据),T(N / b)指的是子问题的规模是N / b,a是指子问题规模等量(都是N / b)的情况下,子问题被调用了多少次,O(N ^ d)是指除了递归调用之外,剩下处理过程的时间复杂度
凡是符合这样行为细节的递归算法,也就是满足子问题等规模的递归算法,它的时间复杂度都可以直接求:
1)logb(a) < d 时,该算法的时间复杂度是O(N ^ d)
2)logb(a) > d 时,该算法的时间复杂度是O(N ^ logb(a))
3)logb(a) == d 时,该算法的时间复杂度是O(N ^ d * log(N))
其中,logb(a)表示以b为底a的对数
在归并排序中,a = 2,b = 2,d = 1(因为要将help中的数据复制回原数组,所以额外空间复杂度是O(N),所以d = 1),故归并排序的时间复杂度为O(N * log (N)).
归并排序的额外空间复杂度解析:
help数组最长是N,所以归并排序的额外空间复杂度是O(N)