归并排序算法

归并排序递归与非递归实现

一定要记住下面这张图!

归并排序就是把大问题一步一步拆成小的子问题
直到子问题不能再拆分
然后开始处理最小子问题,即开始合并操作,直到最后排序结束
归并排序类似于二叉树的后序遍历,请读者认真体会

在这里插入图片描述

归并排序(递归版本)

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));
    }
}

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值