归并排序(Java) – 速度与空间有机结合
归并排序也是一个O(nlogn)的算法,之所以称这个算法为速度与空间的有机结合,是因为这个算法既能做到O(nlogn)时间赋值度的效率,又能借助外部的空间进行排序,因为只有数据比较的时候需要将数据存入到主机中进行,别的时候数据都可以存储在外部存储中,当然这种情况下就多了很多数据的读取和写入,效率会有很大影响,但能力还是在的;所以要最大程度发挥出O(nlogn)算法的效率,还是要用内部的存储空间,且需要进行优化;算法实现分自顶向下和自底向上两种~~
归并排序之所以能达到O(nlogn),主要用到了数据结构中的二分法,将庞大的数据拆分成两段,不断分不断分直到只有两个数据时进行比较,比较完合并,然后再两个数据和另外两个数据进行比较,比较完合并,然后再四个数据和另外四个数据进行比较,比较完合并,直至所有数据合并,对比于每个数据都要和别的数据比较一次的O(n2)方法,时间效率大大提升,当然是在数据量庞大的时候;
归并排序
将大数组递归拆分两段到两个比较,因为递归的特性,思路和代码体现就是从大到小地进行递归;
public class MergeSort {
private MergeSort() {}
// 排序主算法,其中arrTemp用来记录当次排序的顺序序列
public static void goSort(Comparable[] arr, Comparable[] arrTemp, int l, int r) {
if(l >= r)
return;
int mid = (l+r)/2;
goSort(arr, arrTemp, l, (l+mid)/2);
goSort(arr, arrTemp, mid+1, r);
// 只有当左边有序序列的最大值大于右边序列的最小值时才有必要进行合并操作,不然就维持原样就好
// 对基本有序序列有奇效
if(arr[mid].compareTo(arr[mid+1]) > 0)
merge(arr, arrTemp, l, r);
}
// 归并方法
public static void merge(Comparable[] arr, Comparable[] arrTemp, int l, int r) {
int mid = (l+r)/2;
int lMark=l, rMark=mid+1; // lMark记录左边序列位置,rMark记录右边序列位置
int mark=l; // 已排好需序位
while(lMark <= mid && rMark <= r) {
if(arr[lMark].compareTo(arr[rMark]) <= 0)
arrTemp[mark++] = arr[lMark++];
arrTemp[mark++] = arr[rMark++];
}
// 上面循环剩下的最大元素序列放到已排好序列后面
while(lMark <= mid)
arrTemp[mark++] = arr[lMark++];
while(rMark <= r)
arrTemp[mark++] = arr[rMark++];
for(int tail=l; tail <= r; tail++) {
arr[tail] = arrTemp[tail];
}
}
// 统一排序算法接口方法
public static void sort(Comparable[] arr) {
Comparable[] arrTemp = new Comparable[arr.length];
goSort(arr, arrTemp, 0, arr.length-1);
}
}
归并排序与希尔排序性能PK赛
比赛规则:
- 对100万个数据进行排序;
- 分随机数序列和基本有序序列两场比赛;
- 基本有序序列的未有序数据数量是200个;
- 所有排序法均已优化;
- 从上到下是归并排序、希尔排序;
随机数序列:
MergeSort : 135ms
ShellSort : 960ms
基本有序序列:
MergeSort : 40ms
ShellSort : 230ms
比赛结果:
- 在面对随机的100万个数据时,O(logn2)的希尔排序和O(nlongn)的归并排序不在一个level上;