归并排序-java语言版

280 阅读3分钟

归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法的一个非常典型的应用。将已有序的子 序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序 表,称为二路归并。

排序原理:
    1、尽可能的一组数据拆分成两个元素相等的子组,并对每一个子组继续拆分,直到拆分后的每个子组的元素个数是 1为止。
    2、将相邻的两个子组进行合并成一个有序的大组。
    3、将相邻的两个子组进行合并成一个有序的大组

-- 原理图:

归并排序原理图.png

-- 归并原理:

归并原理第一次填充.png

归并原理第二次填充.png -- 实现归并原理:

第一步:定义三个指针:int i , p1 , p2 ,i指向辅助数组assist中的开始填充索引,p1指向左子组开始索引,p2指向右子组的开始索引。
int i = lo;          // 定义一个指针,指向assist数组中开始填充的位置
int p1 = lo;         // 定义一个指针,指向第一个数组的开始索引
int p2 = mid + 1;    // 定义一个指针,指向第二个数组的开始索引
第二步:比较左右子组指针处的元素大小,哪个小就往辅助数组assist的i索引处填充。
// 比较左右两边的子组,哪个小哪个填充到assist数组中
while(p1 <= mid && p2 <= hi) {
    if(less(a[p1],a[p2])) {
        assist[i++] = a[p1++];
    }else {
        assist[i++] = a[p2++];
    }
}
第三步:第三个完成后肯定会有一个子组没有完成填充,索引需要定义两个循环如下
// 需要把未填充完的元素继续填充到assist数组中,下面两个循环只会执行一个
while (p1 <= mid) {
    assist[i++] = a[p1++];
}

while (p2 <= hi) {
    assist[i++] = a[p2++];
}
第四步:将辅助数组的元素,拷贝到原始数组中
// 再把数据拷贝到a数组中对应的索引处
for(int index = lo;index <= hi;index++) {
    a[index] = assist[index];
}

-- API设计:

归并排序API设计.png

-- 代码:

/**
 * 归并排序
 */
public class Merge {
    private static Comparable[] assist;     // 归并所需的辅助数组

    // 对数组a中的元素进行排序
    public static void sort(Comparable[] a) {
        assist = new Comparable[a.length];
        int lo = 0;
        int hi = a.length - 1;
        sort(a,lo,hi);
    }

    // 对数组a中从lo到hi的元素进行排序
    public static void sort(Comparable[] a,int lo,int hi) {
        // 如果完成分组结束递归
        if(hi <= lo) {
            return;
        }

        // 取分组中间值
        int mid = lo + (hi - lo) / 2;

        // 对lo到mid之间的元素进行排序
        sort(a,lo,mid);
        // 对mid+1到hi之间的元素进行排序
        sort(a,mid+1,hi);

        // 进行归并
        marge(a,lo,mid,hi);
    }

    private static void marge(Comparable[] a,int lo,int mid,int hi) {
        int i = lo;          // 定义一个指针,指向assist数组中开始填充的位置
        int p1 = lo;         // 定义一个指针,指向第一个数组的开始索引
        int p2 = mid + 1;    // 定义一个指针,指向第二个数组的开始索引

        // 比较左右两边的子组,哪个小哪个填充到assist数组中
        while(p1 <= mid && p2 <= hi) {
            if(less(a[p1],a[p2])) {
                assist[i++] = a[p1++];
            }else {
                assist[i++] = a[p2++];
            }
        }

        // 需要把未填充完的元素继续填充到assist数组中,下面两个循环只会执行一个
        while (p1 <= mid) {
            assist[i++] = a[p1++];
        }

        while (p2 <= hi) {
            assist[i++] = a[p2++];
        }

        // 再把数据拷贝到a数组中对应的索引处
        for(int index = lo;index <= hi;index++) {
            a[index] = assist[index];
        }
    }

    //比较v元素是否小于w元素
    private static boolean less(Comparable v, Comparable w) {
        return v.compareTo(w) < 0;
    }
}

-- 测试代码:

public class MargeTest {
    public static void main(String[] args) throws Exception {
        Integer[] arr = {8, 4, 5, 7, 1, 3, 6, 2};
        Merge.sort(arr);
        System.out.println(Arrays.toString(arr));
    }
}

-- 运行效果图:

归并排序运行效果图.png

@ 以上内容属于个人笔记