归并排序-算法

归并排序:https://blog.csdn.net/qq_37084904/article/details/119217434

主体思想:一列数组:将其分成两个数组,通过一个第三个数组放置两个数组中较小的不断循环得到一个升序的数组。

[8,7,6,5,4,3,2,1]
第一步:分组:[8,7,6,5][4,3,2,1] 
		归并:
拆分:

public static int[] Merge_Sort(int[] arr, int start, int end) {
        //当start==end时,此时分组里只有一个元素,所以这是临界点
        if (start < end) {
            //分成左右两个分组,再进行递归
            int mid = (start + end) / 2;
            //左半边分组
            Merge_Sort(arr, start, mid);
            //右半边分组
            Merge_Sort(arr, mid + 1, end);
            //递归之后再归并归并一个大组
            Merge(arr, start, mid, end);
        }
        return arr;
    }

归并:

public static void Merge(int[] arr, int start, int mid, int end) {
    //左边分组的起点i_start,终点i_end,也就是第一个有序序列
    int i_start = start;
    int i_end = mid;
    //右边分组的起点j_start,终点j_end,也就是第二个有序序列
    int j_start = mid + 1;
    int j_end = end;
    //额外空间初始化
    int[] temp=new int[end-start+1];
    int len = 0;
    //合并两个有序序列
    while (i_start <= i_end && j_start <= j_end) {
        //当arr[i_start]<arr[j_start]值时,将较小元素放入额外空间,反之一样
        if (arr[i_start] < arr[j_start]) {
            temp[len] = arr[i_start];
            len++;
            i_start++;
        } else {
            temp[len] = arr[j_start];
            len++;
            j_start++;
        }
    }
}

这里有个代码小技巧,注意上面合并有序序列的这个循环里面的代码,其实只要一行代码就可以搞定:


//合并两个有序序列
while (i_start <= i_end && j_start <= j_end) {
    temp[len++]=arr[i_start]<arr[j_start]?arr[i_start++]:arr[j_start++];
}

注意:这里还有个小问题,无论是第一个序列还是第二个序列,在比较元素大小最后的时候,有可能会多出来元素。比如说上面的第二个序列的元素9,它在与元素8比较,元素8被存入到额外空间之后,那么它自然就多出来了,我们默认把它放在额外空间的最末尾处;所以我们还需要添加以下代码,写在归并方法里面;


//i这个序列还有剩余元素
while(i_start<=i_end){
    temp[len] = arr[i_start];
    len++;
    i_start++;
}
//j这个序列还有剩余元素
while(j_start<=j_end){
    temp[len] = arr[j_start];
    len++;
    j_start++;
}
2.3,第三个步骤,

2.3,第三个步骤,


//额外空间数据覆盖到原空间
for(int i=0;i<temp.length;i++){
    arr[start+i]=temp[i];
}
循环我
完整代码:

import java.util.Arrays;
 
public class Merge_Sort {
    public static void main(String[] args) {
        int[] arr = {4,2,8,0,5,7,1,3,9};
        System.out.println(Arrays.toString(Merge_Sort(arr, 0, arr.length - 1)));
    }
 
    /**
     * @param arr   初始数组
     * @param start 开始分组
     * @param end   结束分组
     * @return
     */
    public static int[] Merge_Sort(int[] arr, int start, int end) {
        //当start==end时,此时分组里只有一个元素,所以这是临界点
        if (start < end) {
            //分成左右两个分组,再进行递归
            int mid = (start + end) / 2;
            //左半边分组
            Merge_Sort(arr, start, mid);
            //右半边分组
            Merge_Sort(arr, mid + 1, end);
            //递归之后再归并归并一个大组
            Merge(arr, start, mid, end);
        }
        return arr;
    }
 
    //归并方法
    public static void Merge(int[] arr, int start, int mid, int end) {
        //左边分组的起点i_start,终点i_end,也就是第一个有序序列
        int i_start = start;
        int i_end = mid;
        //右边分组的起点j_start,终点j_end,也就是第二个有序序列
        int j_start = mid + 1;
        int j_end = end;
        //额外空间初始化,数组长度为end-start+1
        int[] temp=new int[end-start+1];
        int len = 0;
        //合并两个有序序列
        while (i_start <= i_end && j_start <= j_end) {
            //当arr[i_start]<arr[j_start]值时,将较小元素放入额外空间,反之一样
            if (arr[i_start] < arr[j_start]) {
                temp[len] = arr[i_start];
                len++;
                i_start++;
            } else {
                temp[len] = arr[j_start];
                len++;
                j_start++;
            }
            //temp[len++]=arr[i_start]<arr[j_start]?arr[i_start++]:arr[j_start++];
        }
 
        //i这个序列还有剩余元素
        while(i_start<=i_end){
            temp[len] = arr[i_start];
            len++;
            i_start++;
        }
        //j这个序列还有剩余元素
        while(j_start<=j_end){
            temp[len] = arr[j_start];
            len++;
            j_start++;
        }
        //辅助空间数据覆盖到原空间
        for(int i=0;i<temp.length;i++){
            arr[start+i]=temp[i];
        }
    }

}
posted @ 2022-10-14 11:57  苍白之躯  阅读(31)  评论(0)    收藏  举报