排序算法-归并排序
方法
归并排序是基于归并操作实现的,归并操作比较简单,就是将两个有序的数组合并为一个有序的大数组。
实现了归并操作之后,我们就要思考如何将一个大的数组分成两个有序的数组。只要能将一个大的数组变成两个有序数组,就能用归并操作完成排序了。因此,要排序一个数组,我们可以将其不断地拆分,当拆分到两个数组长度为一或零的时候,就可以直接对其进行归并操作了。归并后的数组变得有序,我们就不断将拆分的数组进行归并操作,最终就能得到一个有序的数组了。
实现
private static int[] aux;
@Override
public void sort(int[] arr) {
aux = new int[arr.length];
sort(arr, 0, arr.length-1);
}
private void sort(int[] arr, int head, int tail) {
if (head >= tail) return;
int mid = (head + tail)/2;
sort(arr, head, mid);
sort(arr, mid + 1, tail);
merge(arr, head, mid, tail);
}
private void merge(int[] arr, int head, int mid, int tail) {
int i = head;
int j = mid + 1;
for (int k = head; k <= tail; k++) {
aux[k] = arr[k];
}
for (int k = head; k <= tail; k++) {
if (i > mid) arr[k] = aux[j++];
else if (j > tail) arr[k] = aux[i++];
else if (aux[i] < aux[j]) arr[k] = aux[i++];
else arr[k] = aux[j++];
}
}
复杂度分析
时间复杂度
因为归并排序是递归实现的,所以我们带入递归的主公式:T (n) = aT(n/b) + f(n)。因为每次拆分后都要进行归并操作,归并操作时间复杂度是O(n),所以f (n)=O(n)。每次划分成2段,所以a=2,每段的大小为数组的二分之一,所以b=2。
得到公式:T (n) = 2T(n/2) + O(n) = 2T(n/2) + O(n^1),得到d=1。可知d=logb a,所以复杂度为O((n^d)*logn) = O( nlogn )
空间复杂度
因为需要一个辅助数组去存放元素,而这个数组大小和需排序数组一样,所以空间复杂度为 O(n)。