引言
归并排序的时间复杂度是O(N*logN),额外空间复杂度是O(N),可以实现做的稳定性。
归并排序的思想是把一个数组分成两半,把每一半都分成两个四分之一,把每个四分之一部分分成八分之一,依次类推,反复的分割数组,直到得到的子数组是只有一个数据项。然后把两个只有一个数据进行比较。创建等于其数据项大小的数组,把数据按大小顺序拷贝到新创建的数组中,把新的数组中的数据按顺序再拷贝回到原数组。排序就排列好了。
如下图
把数组分成两半后
先开始分左半部分 继续分两半 直到分到时单个数为止
如图所示(图画的有点囧),先把数组的元素进行比较。元素1直接返回,右边元素8、7。先排序右侧部分,创建一个两个元素的数组,把元素8和7进行比较,然后按顺序进行排序,排序后就是7和8。再把7和8拷贝的原数组。然后再用元素1与7、8进行比较,左边1比7小 先拷贝1,然后再把7、8拷贝到新数组,在把这个次序按新数组的顺序拷贝到原来数组中去。依次类推,具体代码实现如下:
/**
* 归并排序
* @author whmAdmin
*
*/
public class MergeSort {
public static void mergeSort(int[] arr){
if(null == arr || arr.length < 2){
return;
}
mergeSortTest(arr, 0, arr.length-1);
}
public static void mergeSortTest(int[] arr, int L, int R) {
// 如果左右下坐标相等,返回
if(L == R){
return;
}
// 获取中间下坐标
int mid = L + (R - L) / 2;
// 先排序左部分,左部分是L到mid中间这部分元素
mergeSortTest(arr, L, mid);
// 再排序右部分,右部分是mid中间后一位到R这部分元素
mergeSortTest(arr, mid+1, R);
// 对要排序的数组进行排序操作
mergeSortArray(arr,L,mid,R);
}
public static void mergeSortArray(int[] arr, int L, int mid, int R) {
//创建新数组
int[] arrs = new int[R-L+1];
//设置新数组开始坐标
int i = 0;
// 设置左部分开始指针
int p1 = L;
// 设置右部分开始指针
int p2 = mid + 1;
// 如果左指针坐标小于等于中间左边并且右指针坐标小于等于R最右坐标,继续循环。否则越界停止循环
while(p1<=mid&& p2 <= R){
// 比较左右两个指针上的元素大小,谁小就拷贝到新数组,并且指针位置++
arrs[i++] = arr[p1] < arr[p2]?arr[p1++]:arr[p2++];
}
// 如果左指针位置比右指针所有位置元素都大,需要把剩余左部分全部拷贝到新数组
while(p1<=mid){
arrs[i++] = arr[p1++];
}
// 同理如果右指针位置比左指针所有位置的元素都大,需要把剩余右部分全部拷贝新数组
while(p2<=R){
arrs[i++] = arr[p2++];
}
// 以上左右指针拷贝只能出现一种
// 把排序好的新数组元素拷贝到原数组中
for (int j = 0; j < arrs.length; j++) {
// L+1是要按原位置进行拷贝回去
arr[L+j] = arrs[j];
}
}
}
以上就是归并排序的实现,这种实现使用了递归的方式进行实现的,归并排序存在非递归实现版本。有兴趣的可以进行了解一下。