归并排序算法
一、归并排序的概念
归并:即将两个有序的数组归并成一个更大的有序数组。根据归并这一操作,得出一种简单的递归排序算法:归并排序。要将一个数组排序,可以先(递归地)将它分为两半分别排序,然后将结果归并起来。
归并排序的一个重要性质:它能够保证将任意长度为N的数组排序所需时间和NlogN成正比。它的主要缺点则是:它所需的额外空间和N成正比。
二、原地归并的抽象方法
(一)、原地归并的抽象方法的概念
实现归并的一种直截了当的办法是将两个不同的有序数组归并到第三个数组中,两个数组中的元素应该都实现了Comparable
接口。实现的方法很简单,创建一个适当大小的数组然后将两个输入数组的元素一个个从小到大放入这个数组中。
但是,当用归并将要给大数组排序时,需要进行很多次归并,因此在每次归并时都创建一个新数组来存储排序结果会带来问题。
因此,假如有一种原地归并的方法,就可以先将前半部分排序,然后将后半部分排序,然后再数组中移动元素而不需要额外的空间。但实际上已有的实现都非常复杂,尤其是和使用额外空间的方法相比。
但将原地归并并抽象化仍然是有帮助的,与之对应的是我们的方法merge(a,lo,mid,hi),它将子数组a[lo…mid]和a[mid+1…hi]归并成一个有序的数组并将结果存放在a[lo…hi]中。
(二)、原地归并的抽象方法的代码示例
该方法先将所有元素复制到aux[]中,然后再归并回arr[]中。
在第二个for循环(归并)时进行了4个条件判断:左半边用尽(取右半边的元素)、右半边用尽(取左半边的元素)、右半边的当前元素小于左半边的当前元素(取右半边的元素)以及右半边的当前元素大于等于左半边的当前元素(取左半边的元素)。
public static void merge(Comparable[] arr, int lo, int mid, int hi) {
// 将arr[lo...mid]和a[mid+1...hi]归并
int i = lo;
int j = mid + 1;
Comparable[] aux = new Comparable[arr.length];
for (int k = lo; k <= hi; k++) {
aux[k] = arr[k];
}
for (int k = lo; k <= hi; k++) {
if (i > mid) {
arr[k] = aux[j++];
} else if (j > hi) {
arr[k] = aux[i++];
} else if (less(aux[j], aux[i])) {
arr[k] &#