5、归并排序
归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。其时间复杂度为O(nlogn),空间复杂度为O(n),是稳定的排序算法。
归并排序算法的工作原理如下:
(1)申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
(2)设定两个指针或下标,最初位置分别为两个已经排序序列的起始位置
(3)比较两个指针或下标所指向的元素,选择相对小的元素放入到合并空间,并移动指针或下标到下一位置
(4)重复步骤3直到某一指针或下标超出序列尾,将另一序列剩下的所有元素直接复制到合并序列尾
下面是一个二路归并排序的简单程序:
public class MergeSort {
// 二路归并
// 原理:将两个有序表合并和一个有序表
public static void main(String[] args) {
int[] array = { 4, 2, 8, 9, 5, 7, 6, 1, 3 };
// 未排序数组顺序为
System.out.println("未排序数组顺序为:");
display(array);
mergeSort(array, 0, 1);
System.out.println("经过排序后的数组顺序为:");
display(array);
}
// 遍历显示数组
public static void display(int[] array) {
for (int i = 0; i < array.length; i++) {
System.out.print(array[i] + " ");
}
System.out.println();
}
public static void mergeSort(int[] a, int s, int len) {
// a 数组
// s 第一个有序表的起始下标
// len 每次归并的有序集合的长度
int size = a.length;
int mid = size / (len * 2);
int c = size & ((len * 2) - 1);
// 归并到只剩一个有序集合的时候结束算法
if (mid == 0)
return;
// 进行一趟归并排序
for (int i = 0; i < mid; ++i) {
s = i * 2 * len;
merge(a, s, s + len, (len << 1) + s - 1);
}
// 将剩下的数和倒数一个有序集合归并
if (c != 0)
merge(a, size - c - 2 * len, size - c, size - 1);
// 递归执行下一趟归并排序
mergeSort(a, 0, 2 * len);
}
private static void merge(int[] a, int s, int m, int t) {
// a 数组
// s 第一个有序表的起始下标
// m 第二个有序表的起始下标
// t 第二个有序表的结束下标
int[] tmp = new int[t - s + 1];
int i = s, j = m, k = 0;
while (i < m && j <= t) {
if (a[i] <= a[j]) {
tmp[k] = a[i];
k++;
i++;
} else {
tmp[k] = a[j];
j++;
k++;
}
}
while (i < m) {
tmp[k] = a[i];
i++;
k++;
}
while (j <= t) {
tmp[k] = a[j];
j++;
k++;
}
System.arraycopy(tmp, 0, a, s, tmp.length);
}
}