归并排序和案例解析

概述

排序是数据结构中重要的一个问题领域也是现实生活和面试时比较容易遇到和考到的一个知识点,所以本篇博客就说下归并排序(其他的排序后面也会出博客讲解)
总体介绍:归并排序是一个递归加分治的思想完成的,对于数组问题,总的来说就是把左子数组排好序再把右子数组排好序,最后在对左右有序数组进行归并(即一起排序的过程)。图解如下
归并排序和案例解析_第1张图片

代码分析

public class guibinSort {

    public static void main(String[] args) {
        int[] arr = {7,2,1,9,0};
        sortProcess(arr,0,4);
        for(int i = 0; i < arr.length; i++)
            System.out.print(arr[i]+" ");
    }
    //递归过程
    static void sortProcess(int[] arr,int L,int R){
        if(L==R)//只有一个元素已经有序了
            return;
        int mid = L + ((R-L)>>1);//分治
        //排左子数组
        sortProcess(arr,L,mid);
        //排右子数组
        sortProcess(arr,mid+1,R);
        //其实这里才是真的对子数组排序的步骤
        //即只有数组中元素只有一个元素时才会执行到这一步
        //因为只有一个元素就本身就有序了,这时才会合并
        //体现了对有序数组进行合并的思路
        merge(arr,L,mid,R);
    }

    private static void merge(int[] arr, int l, int mid, int r) {
        int[] help = new int[r - l + 1];//辅佐数组,长度为要合并的两个子数组的长度
        int i = 0;
        int p1 = l;//指向左子数组的指针
        int p2 = mid + 1;//指向右子数组的指针
        while (p1 <= mid && p2 <= r) {//合并过程
        //两子数组中小的元素优先被放入辅佐数组中
            help[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
        }
        while (p1 <= mid) {//若右子数组先遍历完那么就直接把左子数组剩下元素复制到辅佐数组中
            help[i++] = arr[p1++];
        }
        while (p2 <= r) {//若左子数组先遍历完那么就直接把右子数组剩下元素复制到辅佐数组中
            help[i++] = arr[p2++];
        }
        //把辅佐数组中的有序数组复制到原数组中
        for (int j = 0; j < help.length; j++) {
            arr[l + j] = help[j];
        }
    }
}

案例

案例:在一个数组中,每一个数左边比当前数小的数累加起来,叫做这个数组的小和。现在给一个数组求这个数组的小和

思路:其实就是利用归并排序在和并的时候来求小和,其中有序归并的时候两个子数组都是有序数组了那么可以有效利用“有序”这个特点来快速求得小和

public class SmallSum {

    public static void main(String[] args) {
        int[] arr = {1,3,4,2,5};
        System.out.println(sortProcess(arr,0,4));
    }
    //和归并的时候一样
    static int sortProcess(int[] arr,int L,int R){
        if(L == R)//一个数字即自身就有序了,有序就可以合并了
            return 0;
        int mid = L + ((R-L)>>1);
        return sortProcess(arr,L,mid)+
        sortProcess(arr,mid+1,R)+
        merge(arr,L,mid,R);
    }
	//合并的时候大多都一样只是多了一步
    private static int merge(int[] arr, int l, int mid, int r) {
        int[] help = new int[r-l+1];
        int i = 0;
        int left = l;
        int right = mid+1;
        int retVal = 0;
        while(left <= mid && right <= r){
        //这里便是多的一步,仔细体会这步骤就可以知道归并求小和的优势
            retVal += arr[left] < arr[right] ? (r-right+1)*arr[left]:0;//求小和
            help[i++] = arr[left] < arr[right] ? arr[left++]:arr[right++];
        }
        while(left <= mid){
            help[i++] = arr[left++];
        }
        while(right <= r){
            help[i++] = arr[right++];
        }
        for(i = 0; i < help.length; i++){
            arr[l+i] = help[i];
        }
        return retVal;
    }
}

你可能感兴趣的:(数据结构)