归并排序是采用分治策略,将问题分成一些小的问题然后递归求解,让后将得到的结果合并到一起。
归并排序:
时间复杂度是O(nlogn)
最好情况O(nlogn)
最坏情况O(nlogn)
空间复杂度 O(n)
归并排序是占用额外内存的,是稳定的。
图解
合并的具体实现,我们需要借助一个临时数组排序,排好序后将临时数组中的元素复制到原先数组中即可。
/**
* 分 + 合方法
* @param arr
* @param left
* @param right
* @param temp
*/
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);
}
}
/**
* 合并的方法
* @param arr 排序的原始数组
* @param left 左边有序序列的初始索引
* @param mid 中间索引
* @param right 右边索引
* @param temp 做中转的数组
*/
public static void merge(int[] arr,int left,int mid,int right,int[] temp){
//初始化i,左边有序序列的初始索引
int i = left;
//初始化j,右边有序序列的初始索引
int j = mid +1;
//指向temp数组的当前索引
int t = 0;
//(一)先把左右两边(有序)的数据按照规则填充到temp数组
//直到左右两边有序序列,有一边处理完毕为止
while (i <= mid && j <= right){
//如果左边的有序序列的当前元素,小于等于右边有序序列的当前元素
//即将左边的当前元素,填充到temp数组
if (arr[i] <= arr[j]){
temp[t] = arr[i];
t += 1;
i += 1;
}else {
//反之,将右边有序序列的当前元素,填充到temp数组
temp[t] = arr[j];
t += 1;
j += 1;
}
}
//(二)把剩余数据的一边的数据依次全部填充到temp
while (i <= mid){
//左边的有序序列还有剩余元素,就全部填充到temp
temp[t] = arr[i];
t += 1;
i += 1;
}
while (j <= right){
temp[t] = arr[j];
t += 1;
j += 1;
}
//(三)将temp数组的元素拷贝到arr
t = 0;
int tempLeft = left;
while (tempLeft <= right){
arr[tempLeft] = temp[t];
t += 1;
tempLeft += 1;
}
}