归并排序理解:二分法对数组排序

首先上图:

请添加图片描述

请添加图片描述

下面这个图就是,一开始分成了左右两部分,左边是4578,右边是1236,然后分别拿左右两部分的第一个数字进行比较,发现右边的的1小于左边的4,然后右边部分指针右移一个单位,变成了2去和左边的4比较大小,这样以此类推…

请添加图片描述

0:我们一开始将左边的第一个数字用i来指向,右边第一个数字用j来指向,那么我们可以一开始定义一个方法


 /**
     * @arr 排序的原始数组
     * @param left 左边有序序列的初始索引
     * @param mid  中间索引
     * @param right  右边索引
     * @param temp  做中转的数组
     */

    public static  void merge(int[] arr,int left, int mid, int right,int[] temp){
    
    
        int i = left; // 初始化i,左边这个有序序列的初始索引
        int j = mid +1; //初始化j,右边这个有序序列的初始索引
        int t = 0; // 指向temp数组的当前索引

1:然后我们进入到了第一个循环

先把左右两边(有序)的数据按照规则填充到temp数组中,知道左右两边的有序序列有一边处理完毕为止

(1)i和j分别代表左右两部分的第一个数字,然后用他两作比较,将小的那个数字现存放到临时数组temp中,然后temp和较小的左边部分指针都要加一**

   while (i<= mid && j<=right){
    
     //继续
            // 如果左边的有序序列的当前元素,小于等于右边有序序列的当前元素
            // 即将左边的当前元素,拷贝到temp数组
            // 然后t要往后移动一下
            if (arr[i] <= arr[j]){
    
    
                temp[t] = arr[i];
                t+=1;
                i+=1;
            }

        }

(2)如果是右边的小就是这个情况,使用else

  while (i<= mid && j<=right){
    
     //继续
            // 如果左边的有序序列的当前元素,小于等于右边有序序列的当前元素
            // 即将左边的当前元素,填充到temp数组
            // 然后t要往后移动一下
            if (arr[i] <= arr[j]){
    
    
                temp[t] = arr[i];
                t+=1;
                i+=1;
            }else {
    
     //反之,将右边有序序列的当前元素填充到temp数组
                temp[t] = arr[j];
                t+=1;
                j+=1;
            }

        }

2:我们进入第二大步骤,按照我们的图片所示,我们会出现两个情况就是当右边已经全部填入temp但是左边还留有数字或者左边全部填入temp但是右边还有数字的时候:我们需要做一个循环:

 //把有剩余数据的一边的数据依次全部填充到temp去
        while (i <= mid){
    
     //左边的有序序列还有剩余的元素,就全部填充到temp中
            temp[t] = arr[i];
            t+=1;
            i+=1;

        }
        while (j <= right){
    
     //右边的有序序列还有剩余的元素,就全部填充到temp中
            temp[t] = arr[j];
            t+=1;
            j+=1;

        }

3:进入第三大步骤,也就是我们的拷贝过程,我们要将得到的temp数字拷贝到原来的数组中去,但是这个拷贝不是一下子就把八个数字全部拷贝进去的,他有一个过程,请添加图片描述

首先是我们定义一个新的指针tempLeft,然后初始为0,right是1,然后第二次合并tempLeft变成了2,right变成了3,然后再整体合并一下,tempLeft变成了0,right变成了3,同理,右边也是这样,最后tempLeft成了0right成了7就把全部的数字拷贝进去了。(相当于:01->23-> 03-> 45-> 67-> 47-> 07)

     //(三)
        //将temp数组中的元素拷贝到arr
        // 并不是每一次都拷贝所有
        t = 0;
        int tempLeft = left;

        //第一次合并时 tempLeft=0,right = 1  //  tempLeft = 2  right = 3 // tempLeft = 0  right = 3
        // 最后一次 tempLeft = 0 right = 7
        while (tempLeft <= right){
    
    
            arr[tempLeft] = temp[t];
            t +=1;
            tempLeft+=1;
        }

4:第四大步:我们前面这几步相当于一直是从已经分解好了那个时候开始的,所以我们需要使用递归调用将原数组分解:

  //分加和的方法
    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);


        }

    }

5:第五步:编写主方法,主方法中定义初始数组和临时数组,调用方法

public class MergetSort {
    
    
    public static void main(String[] args) {
    
    
        int arr[] = {
    
    8,4,5,7,1,3,6,2};
        int temp[] = new int[arr.length]; // 归并排序需要一个额外空间
        mergeSort(arr,0, arr.length-1,temp);
        System.out.println("归并排序后="+ Arrays.toString(arr));

    }

最后需要再递归分解的时候加入合并:

  //分加和的方法
    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);


        }

    }

全部代码:

package 二分法排序;

import java.util.Arrays;

/**
 * @author ${范涛之}
 * @Description
 * @create 2021-11-04 0:13
 */
public class MergetSort {
    
    
    public static void main(String[] args) {
    
    

        int arr[] = {
    
    8,4,5,7,1,3,6,2};
        int temp[] = new int[arr.length]; // 归并排序需要一个额外空间
        mergeSort(arr,0, arr.length-1,temp);
        System.out.println("归并排序后="+ Arrays.toString(arr));

    }


    //分加和的方法
    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);


        }

    }


    // 首先写合并的方法
    // 需要四个参数,原数组,左指针,右指针,中间值,还有一个临时数组temp

    /**
     * @arr 排序的原始数组
     * @param left 左边有序序列的初始索引
     * @param mid  中间索引
     * @param right  右边索引
     * @param temp  做中转的数组
     */

    public static  void merge(int[] arr,int left, int mid, int right,int[] temp){
    
    
        System.out.println("xxx");
        int i = left; // 初始化i,左边这个有序序列的初始索引
        int j = mid +1; //初始化j,右边这个有序序列的初始索引
        int t = 0; // 指向temp数组的当前索引


        // (一)
        //先把左右两边(有序)的数据按照规则填充到temp数组中,知道左右两边的有序序列有一边处理完毕为止
        while (i<= mid && j<=right){
    
     //继续
            // 如果左边的有序序列的当前元素,小于等于右边有序序列的当前元素
            // 即将左边的当前元素,填充到temp数组
            // 然后t要往后移动一下
            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中
            temp[t] = arr[j];
            t+=1;
            j+=1;

        }



        //(三)
        //将temp数组中的元素拷贝到arr
        // 并不是每一次都拷贝所有
        t = 0;
        int tempLeft = left;

        //第一次合并时 tempLeft=0,right = 1  //  tempLeft = 2  right = 3 // tempLeft = 0  right = 3
        // 最后一次 tempLeft = 0 right = 7
        System.out.println("tempLeft="+tempLeft+" right="+right);
        while (tempLeft <= right){
    
    
            arr[tempLeft] = temp[t];
            t +=1;
            tempLeft+=1;
        }



    }
}

运行结果:

请添加图片描述

猜你喜欢

转载自blog.csdn.net/justleavel/article/details/121133475