1、归并排序
时间复杂度O(N*logN),额外空间复杂度O(N)(具体分析过程请看:递归相关算法的时间复杂度分析(master公式引入))
归并排序又分为自顶向下和自底向上两种思路,这里着重说一下自顶向下
1.1 自顶向下
最主要的是这个merge的外排思想,怎么将两个数组合并起来并且排好序(其实下面代码中并不需要递归,直接 merge(arr, lo, mid, hi);就可以了,但是递归后将数组分为更小的组合然后再mergr效率会更高,这也是归并排序效率比前面几个排序算法高的原因。
外排merge的代码,我们简化后看一下,其实就是将两个数组(无论有没有序,就算没有序,我们用判断依然可以排序)来一个一个数进行比较,这里用两个指针指针两个数组的第一个数(也就是 i 和 j),,加上判断语句,这样就遍历了两个数组(注,我这里只是遍历),然后加上我们的辅助数组等操作,来达到排序的目的(在一些其他题,如小和问题、逆序问题,都用到了这个外排的思想)
(最重要的思路就是用外排的思想来遍历两个数组,然后我们可以在遍历的过程中做其他的操作)
下面简化后的外排代码:遍历两个数组
private void merge(int[] arr, int lo, int mid, int hi) {
int i = lo;
int j = mid + 1;
for (int k = lo; k <= hi; k++) {
arrSup[k] = arr[k];
}
for (int k = lo; k <= hi; k++) {
if (i > mid) { //左半边用尽,用右半边元素
j++;
} else if (j > hi) { //右半边用尽,用左半边元素
i++;
} else if (arrSup[i] > arrSup[j]) { //如果左边最小值大于最右边,先用右半边
j++;
} else { //用完再用左半边
i++;
}
}
}
最终的自顶向下的归并排序代码:
package cn.nupt.sort;
/**
* @Description: 归并排序(自顶向下)
*
* @author PizAn
* @date 2019年1月19日 下午9:03:31
*
*/
public class MergeSort {
private int[] arrSup; // 归并排序所需的辅助数组
public void mergeSort(int[] arr) {
arrSup = new int[arr.length]; // 对辅助数组分配空间
sort(arr, 0, arr.length - 1);
show(arr); // 遍历
}
private void sort(int[] arr, int lo, int hi) {
if (lo >= hi)
return;
int mid = (lo + hi) / 2;
sort(arr, lo, mid);
sort(arr, mid + 1, hi);
merge(arr, lo, mid, hi);
}
//融合两个已经排序过的数组
private void merge(int[] arr, int lo, int mid, int hi) {
int i = lo;
int j = mid + 1;
for (int k = lo; k <= hi; k++) {
arrSup[k] = arr[k];
}
for (int k = lo; k <= hi; k++) {
if (i > mid) { //左半边用尽,用右半边元素
arr[k] = arrSup[j++];
} else if (j > hi) { //右半边用尽,用左半边元素
arr[k] = arrSup[i++];
} else if (arrSup[i] > arrSup[j]) { //如果左边最小值大于最右边,先用右半边
arr[k] = arrSup[j++];
} else { //用完再用左半边
arr[k] = arrSup[i++];
}
}
}
// 遍历的实现
private void show(int[] arr) {
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}
1.2 自底向上
package cn.nupt.sort;
/**
* @Description: 归并排序(自底向上)
*
* @author PizAn
* @date 2019年1月20日 上午9:02:05
*
*/
public class MergeSort {
private int[] arrSup; // 归并排序所需的辅助数组
public void mergeSort(int[] arr) {
int num = arr.length;
arrSup = new int[num]; // 对辅助数组分配空间
for (int sz = 1; sz < num; sz = 2 * sz) {
for (int lo = 0; lo < num - sz; lo += 2 * sz) {
merge(arr, lo, lo + sz - 1, Math.min(lo + 2 * sz - 1, num - 1));
}
}
show(arr);
}