一定要记住下面这张图!
归并排序就是把大问题一步一步拆成小的子问题
直到子问题不能再拆分
然后开始处理最小子问题,即开始合并操作,直到最后排序结束
归并排序类似于二叉树的后序遍历,请读者认真体会
归并排序(递归版本)
public class MergeSort{
//归并排序递归版本
//时间o(nlongn)
//空间o(n)
private void sort(int[] data){
if(data == null || data.length < 2) return;
sort(data,0,data.length-1);
}
//left:数组的左边界
//right:数组的右边界
private void sort(int[] data , int left , int right){
//递归终止条件
if(left == right) return;
int mid = (left + right) / 2;
//把大问题划分成子问题
//对[left,right]区间上的归并排序的排序划分成对[left,mid]和[mid+1,right]两个区间上的归并排序
sort(data,left,mid);
sort(data,mid+1,right);
//调用归并方法
merge(data,left,mid,right);
}
//
private void merge(int[] data, int left, int mid, int right) {
int num = right - left + 1;
//临时数组
int[] tmp = new int[num];
int i = left;
int j = mid + 1;
int tmpPos = 0;
while (i <= mid && j <= right){
if(data[i] <= data[j]) tmp[tmpPos++] = data[i++];
else tmp[tmpPos++] = data[j++];
}
while(i <= mid) tmp[tmpPos++] = data[i++];
while(j <= right) tmp[tmpPos++] = data[j++];
//临时数组要拷贝到原数组
for(tmpPos = 0 ; tmpPos < tmp.length ; left++ , tmpPos++ ){
data[left] = tmp[tmpPos];
}
}
public static void main(String[] args) {
int[] data = new int[]{34, 33, 12, 78, 21, 1, 98, 100};
new MergeSort().sort(data);
System.out.println(Arrays.toString(data));
}
}
归并排序(非递归版本)
非递归版本难点在于处理边界条件
使用两轮循环,第一轮用size从1开始指数级增大,第二轮就是进行归并操作了。
public class MergeSort {
//归并排序非递归
//时间o(nlongn)
//空间o(n)
public void sortBU(int[] data){
if(data == null || data.length <= 1) return;
int len = data.length;
for(int size = 1 ; size < len ; size *= 2){
for(int left = 0 ; left < len - size ; left += 2 * size){
int right = Math.min(left+2*size-1,len-1);
int mid = left + size - 1;
merge(data,left,mid,right);
}
}
}
private void merge(int[] data, int left, int mid, int right) {
int num = right - left + 1;
//临时数组
int[] tmp = new int[num];
int i = left;
int j = mid + 1;
int tmpPos = 0;
while (i <= mid && j <= right){
if(data[i] <= data[j]) tmp[tmpPos++] = data[i++];
else tmp[tmpPos++] = data[j++];
}
while(i <= mid) tmp[tmpPos++] = data[i++];
while(j <= right) tmp[tmpPos++] = data[j++];
//临时数组要拷贝到原数组
for(tmpPos = 0 ; tmpPos < tmp.length ; left++ , tmpPos++ ){
data[left] = tmp[tmpPos];
}
}
public static void main(String[] args) {
int[] data = new int[]{34, 33, 12, 78, 21, 1, 98, 100};
new MergeSort().sortBU(data);
System.out.println(Arrays.toString(data));
}
}