01
归并排序
将待排序的数列分成若干个长度为1的子数列,然后将这些数列两两合并;得到若干个长度为2的有序数列,再将这些数列两两合并;得到若干个长度为4的有序数列,再将它们两两合并;直接合并成一个数列为止。这样就得到了我们想要的排序结果。
02
—
演绎过程
分解 – 将当前区间一分为二,即求分裂点 mid = (low + high)/2;
求解 – 递归地对两个子区间a[low…mid] 和 a[mid+1…high]进行归并排序。递归的终结条件是子区间长度为1。
合并 – 将已排序的两个子区间a[low…mid]和 a[mid+1…high]归并为一个有序的区间a[low…high]。
03
—
时间复杂度
时间复杂度:O(NlgN)
稳定性:稳定算法
04
—
代码实现
//归并排序
/**
* @param arr 原始数组
* @param left 左边有序序列的初始索引
* @param right 右边有序序列的初始索引
* @param mid 中间索引
* @param temp 做中转的数组
*/
public static void merge(int[] arr,int left,int mid,int right,int[] temp) {
int i = left; //初始化i左边序列的初始化索引
int j = mid + 1;//初始化j右边序列的初始化索引
int t = 0;//指向temp数组的当前索引
//把左右两边的有序序列的数据按照规则填充到temp数组中,
//直到左右两边的有序序列有一边处理完为止,
while (i <= mid && j <= right) {
//如果左边有序序列元素小于右边序列的元素,
//就将左边序列的当前元素,填充到temp中
if (arr[i] <= arr[j]) {
temp[t] = arr[i];
i+=1;
t+=1;
} else { //反之亦然
temp[t] = arr[j];
t+=1;
j+=1;
}
}
//把左右两边剩余的数据依次全部填充到temp中
//剩余左边填充
while (i <= mid ) {
temp[t] = arr[i];
i+=1;
t+=1;
}
//剩余右边填充
while (j <= right ) {
temp[t] = arr[j];
j+=1;
t+=1;
}
//数组拷贝,不是每次都拷贝所有
t = 0;
int tempLeft = left;
while (tempLeft <= right) {
arr[tempLeft] = temp[t];
t += 1;
tempLeft += 1;
}
}
//分+合的办法
public static void mergeSort(int[] arr,int left,int right,int[] temp) {
if (left < right) {
int mid = (left + right) / 2;
//向左递归分解
mergeSort(arr,left,mid,temp);
//向右递归分解
mergeSort(arr,mid + 1,right,temp);
//合并
merge(arr,left,mid,right,temp);
}
}
05
—
总结
归并排序算法演绎过程一目了然,很容易理解,但是对于他的代码实现还是有些难度的。
主要是使用了递归思想,重点和难点也在使用递归的这点。
在归并排序中,有两次递归分别为向左和向右递归,一般来讲我们都是先向左递归,在这其中每一次递归过程中再去向右递归。每一次递归的参数不同,最后在实现排序。