您的位置:首页 > 其它

归并排序(MergeSort)

2016-11-11 10:56 323 查看

1 归并排序

归并排序是建立在归并操作上的一种有效的排序算法,该算法和快速排序都是采用分治法来设计算法的,区别在于归并排序把数组分为两个基本等长(最多相差一个元素)的子数组,分别排好序之后还要进行归并操作,而快速排序在拆分子数组的时候则有所不同,其取一个基准元素,拆分之后基准元素左边的元素都比基准元素小,右边的元素都不小于基准元素,这样只需要分别对两个子数组排序即可,不再像归并排序一样需要归并操作。归并排序是稳定的算法,其最坏的时间复杂度是
O(n^2)
,其最好的时间复杂度是
O(nlogn)
.

2 归并过程

假设有数组 a,比较 a[i] 和 a[j] 的大小,若 a[i] ≤ a[j],则将第一个有序表中的元素 a[i] 复制到 r[k] 中,并令 i 和 k 分别加上 1;否则将第二个有序表中的元素 a[j] 复制到 r[k] 中,并令 j 和 k 分别加上 1,如此循环下去,直到其中一个有序表取完,然后再将另一个有序表中剩余的元素复制到 r 中从下标 k 到下标 t 的单元。归并排序的算法我们通常用递归实现,先把待排序区间 [s,t] 以中点二分,接着把左边子区间排序,再把右边子区间排序,最后把左区间和右区间用一次归并操作合并成有序的区间 [s,t].

3 归并举例

假设桌子上有两堆排好序(从小到大)的牌,每一次从两堆里面各抽取一张,比较一下两张的大小,如果两张一样大,都取出放到目标数组,否则取出较小的放到目标数组,另外一个放回原堆里面。接下来,重复上述过程,直到一堆扑克牌取完,再将另一堆扑克牌直接插入目标组即可。从上述描述中可知,归并排序需要额外的空间来存储临时数据。

4 Java代码

public class MergeSort {
public static void main(String[] args) {
int[] arr = {3, 2, 1, 0, -1, -2, -3};
System.out.println("Before sort:");
printArray(arr);
mergeSort(arr);
System.out.println("After sort:");
printArray(arr);
}

public static void mergeSort(int[] arr) {
sortarr(arr, 0, arr.length - 1);
}

private static void sortarr(int[] arr, int start, int end) {   //将数组进行排序操作
if (start == end) {  //单个元素直接返回
return;
}
int sortSize = end - start + 1;  //计算数组总长度
int seperate;  //设置分割元素
if (sortSize % 2 == 0) {
seperate = start + sortSize / 2 - 1;
} else {
seperate = start + sortSize / 2;
}
sortarr(arr, start, seperate);
sortarr(arr, seperate + 1, end);
mergearr(arr, start, seperate, end);
}

private static void mergearr(int[] arr, int start, int seperate, int end) { //将数组进行归并操作
int totalSize = end - start + 1;
int size1 = seperate - start + 1;
int size2 = end - seperate;
//分别创建与两个子组长度相等的数组
int[] arr1 = new int[size1];
int[] arr2 = new int[size2];
//分别将两个子组中的元素存储到新创建的两个数组中
for (int i = 0; i < size1; i++) {
arr1[i] = arr[start + i];
}
for (int i = 0; i < size2; i++) {
arr2[i] = arr[seperate + 1 + i];
}
int mergeCount = 0;
int index1 = 0;
int index2 = 0;
while (mergeCount < totalSize) {
// 先检查有没有其中的一个数组已经处理完
if (index1 == size1) {
for (int i = index2; i < size2; i++) {
arr[start + mergeCount] = arr2[i];
mergeCount++;
index2++;
}
} else if (index2 == size2) {
for (int i = index1; i < size1; i++) {
arr[start + mergeCount] = arr1[i];
mergeCount++;
index1++;
}
} else {  //如果两个子组都没有处理完,则进行以下操作
int value1 = arr1[index1];
int value2 = arr2[index2];
if (value1 == value2) {
arr[start + mergeCount] = value1;
arr[start + mergeCount + 1] = value1;
mergeCount += 2;
index1++;
index2++;
} else if (value1 < value2) {
arr[start + mergeCount] = value1;
mergeCount++;
index1++;
} else if (value1 > value2) {
arr[start + mergeCount] = value2;
mergeCount++;
index2++;
}
}
}
}

public static void printArray(int[] arr) {  //打印数组
System.out.print("{");
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]);
if (i < arr.length - 1) {
System.out.print(", ");
}
}
System.out.println("}");
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: