归并排序

归并排序

归并排序的核心思想是分而治之,就是将大问题拆分成子问题,分别对子问题进行求解之后,并将所有的子问题的解合并之后即可。这便是其中的三个解题步骤。分解,解决,合并

场景0:现有数组([2,5,3,1,4]),求这个数组的从小到大排序后数组表现。

  • 分解。因为单独一个数肯定是有序的,所以,要分解的子问题目的就是分解成一个只含有小数组。第一次分解为2个数组,第二次分解为4,依次类推。直到分解为n个子数组为止
原数组					[2	5	3	1	4]
					/					
第一次分解			[2 5 3]				[1 4]
				  /                    /    
第二次分解		[2 5] 	   [3]         [1]    [4]
			   /   	  
第三次分解	   [2]	[5] 	[3]		  [1]	[4]
  • 合并。对于两个有序的数组进行合并是一个比较简单的事情。创建一个额外数组,然后每次比较分别两个数组的中的最小值后将最小值删除并且有序放入额外数组中。将左右两个数组都取空之后,额外数组的排序也就完成了。如下列所示。
分解后数组	   [2]	[5] 	[3]		  [1]	[4]
					/
第一次合并		[2 5]		[3]		  [1] 	[4]
						    /        	   /
第二次合并			   [2 3 5]			[1 4]
										/
合并之后						[1 2 3 4 5]

根据上面的情况的可以判断,无论是否是计数还是偶数,分解是都是成为了n个数组。合并的过程从开始到最后,每次都是两个数组进行合并。为什么会这样,仔细想一想就会明白了

归并排序demo

下列是我根据最初的<<算法>>中的分治抄袭出来的,代码多一点,但是容易理解。

package Sort;

import java.util.Arrays;

/**
 * 合并排序
 *
 * @author Ldity
 * @date 2020/8/10 21点48分
 */
public class MergeSort {
    private static final int[] nums = {2,51,3,21,4,512,54};
    public static void merge(int[] arr, int left, int mid, int right){
        int n = arr.length;
        int length = right - left + 1;
        int[] tmp = new int[length];
        int i = left;
        int j = mid + 1;
        int k = 0;

        while(i <= mid && j <= right){
            if(arr[i] < arr[j]){
                tmp[k++] = arr[i++];
            }
            else {
                tmp[k++] = arr[j++];
            }
        }

        while(i <= mid) tmp[k++] = arr[i++];
        while(j <= right ) tmp[k++] = arr[j++];
        System.arraycopy(tmp, 0, arr, left, length);
    }

    public static void mergeSort(int[] arr, int left, int right){
        if (left < right){
            int mid = (right + left) / 2;
            mergeSort(arr, left, mid);
            mergeSort(arr, mid + 1, right);
            merge(arr, left, mid, right);
        }
    }

    public static void main(String[] args){
        int left = 0;
        int right = nums.length - 1;
        mergeSort(nums, left, right);
        System.out.println(Arrays.toString(nums));
    }
}

下列这个是我根据acwing中y总的算法进行学习之后得到的。更为简单,但是难懂一点

 /**
     * 这是Acwing中的模板题,更加简洁,思想也比较明确
     *
     * @param arr - 待排序数组
     * @param l - 左边界
     * @param r - 右边界
     */
    public static void merge_sort(int[] arr, int l , int r){
        //终止条件
        if ( l >= r) return;

        int i = l;
        int mid = l + r >> 1;
        int j = mid + 1;

        // 开始分
        merge_sort(arr, l , mid);
        merge_sort(arr, j, r);

        int k = 0;
        int[]  temp = new int[r - l  + 1];
        // 合并两个有序序列
        while (i <= mid && j <= r){
            if (arr[i] < arr[j]) {
                temp[k++] = arr[i++];
            } else{
                temp[k++] = arr[j++];
            }
        }


        // 处理其中一个数组剩下部分
        while (i <= mid ) temp[k++]= arr[i++];
        while (j <= r) temp[k++] = arr[j++];


        // 复制到原有数组中
        for (i = l, j = 0; i <= r; j++, i++){
            arr[i] = temp[j];
        }
    }
原文地址:https://www.cnblogs.com/Di-iD/p/13785067.html