算法学习记录010_归并排序

方式1:

package com.study.data.structures.sort;

import java.util.Arrays;

/**
 * 归并排序:
 */
public class MergeSort {
    //当数组长度小于阈值的时候就开始排序,可以通过修改阈值来调节排序速度,但是并不是越大越好
    private final static int THRESHOLD = 2;

    public static int[] sort(int[] arr) {
        if (arr.length < THRESHOLD) {
            //排序,有了数组,在此处可以自定义排序方式。
            quickSort(arr, 0, arr.length - 1);
            return arr;
        } else {
            //大于阈值,则继续分割数组
            int mid = (0 + arr.length) / 2;
            //不包括mid所指向的元素
            int[] left = Arrays.copyOfRange(arr, 0, mid);
            int[] right = Arrays.copyOfRange(arr, mid, arr.length);
            return merge(sort(left), sort(right));
        }
    }

    private static int[] merge(int[] left, int[] right) {
        int[] result = new int[left.length + right.length];
        for (int index = 0, leftIndex = 0, rightIndex = 0; index < result.length; index++) {
            if (leftIndex >= left.length) {//此时说明左边数组数据已经被取完,后续操作右边数组数据即可
                result[index] = right[rightIndex++];
            } else if (rightIndex >= right.length) {//此时说明右边数组数据已经被取完,后续操作左边数组数据即可
                result[index] = left[leftIndex++];
            } else if (left[leftIndex] > right[rightIndex]) {//如果左边元素大于右边元素,那么就将右边元素先放入数组
                result[index] = right[rightIndex++];
            } else {//如果左边元素小于等于右边元素,那么就将左边元素先放入数组
                result[index] = left[leftIndex++];
            }
        }
        return result;
    }


    /**
     * @param arr   需要排序的数组
     * @param left  最左边的位置
     * @param right 最右边的位置
     */
    public static void quickSort(int[] arr, int left, int right) {
        int l = left;
        int r = right;
        int middle = (left + right) / 2;
        int middleValue = arr[middle];
        int temp = 0;
        //[-11, 4, 2, 1, 3, 6, 9]
        while (l < r) {
            while (arr[l] < middleValue) {
                l += 1;
            }

            while (arr[r] > middleValue) {
                r -= 1;
            }
            //左右箭头相遇,说明此时数据已经根据middleValue分类完毕
            if (l >= r) {
                break;
            }

            temp = arr[l];
            arr[l] = arr[r];
            arr[r] = temp;

            if (arr[l] == middleValue) {
                l += 1;
            }
            if (arr[r] == middleValue) {
                r -= 1;
            }
        }
//        System.out.println(Arrays.toString(arr));
        //不加这个判断就是在一直递归调用
        if (l == r) {
            l += 1;
            r -= 1;
        }

        if (r > left) {
            quickSort(arr, left, r);
        }

        if (l < right) {
            quickSort(arr, l, right);
        }
    }

    public static void main(String[] args) {
        int[] arr = {9, 4, 6, 1, 5, 11};
        int[] sort = sort(arr);
        System.out.println(Arrays.toString(sort));

        int[] arrays = new int[8000000];
        for (int i = 0; i < 8000000; i++) {
            arrays[i] = (int) (Math.random() * 8000000);
        }

        new Thread(() -> {
            long start = System.currentTimeMillis();
            sort(Arrays.copyOf(arrays, arrays.length));
            long end = System.currentTimeMillis();
            System.out.println("归并排序所花时间::" + (end - start));
        }).start();

    }
}

方式2:

package com.study.data.structures.sort;

import java.util.Arrays;

/**
 * 归并排序:
 * 以长度{9, 4, 6, 1, 5, 11};为例
 * 第一步:
 * 调用sort方法left=0,right=5
 * middle=2
 *
 * 第二步
 * 调用sort方法left=0,right=2
 * middle=1
 *
 * 第三步
 * 调用sort方法left=0,right=1
 * middle=0,
 *
 * 第四步
 * 调用sort方法left=0,right=0。因为left==right,所以该方法弹栈
 *
 * 第五步
 * 调用sort方法left=1,right=1。因为left==right,所以该方法弹栈
 *
 * 第六步 合并1
 * 调用merge方法left=0,middle=0,right=1
 * 此时arr={4,9,6,1,5,11}
 *
 * 第7步
 * 调用sort方法left=2,right=2。因为left==right,所以该方法弹栈
 *
 * 第8步 合并2
 * 调用merge方法left=0,middle=1,right=2
 * 此时={4,6,9,1,5,11}
 *
 * 第9步
 * 调用sort方法left=3,right=5。
 * middle=4
 *
 * 第10步
 * 调用sort方法left=3,right=4;
 * middle=3
 *
 * 第11步
 * 调用sort方法left=3,right=3。因为left==right,所以该方法弹栈
 *
 * 第12步
 * 调用sort方法left=4,right=4。因为left==right,所以该方法弹栈
 *
 * 第13步 合并3
 * 调用merge方法left=3,middle=3,right=4
 * 此时arr={4,6,9,1,5,11}
 *
 * 第14步
 *  调用sort方法left=5,right=5。因为left==right,所以该方法弹栈
 *
 * 第15步 合并4
 * 调用merge方法left=3,middle=4,right=5
 * 此时arr={4,6,9,1,5,11}
 *
 * 第16步 合并5
 * 调用merge方法left=0,middle=2,right=5
 * 此时arr={1,4,5,6,9,11}
 */
public class MergeSort2 {
    //当数组长度小于阈值的时候就开始排序
    private final static int THRESHOLD = 2;

    private static void sort(int[] arr, int left, int right, int[] temp) {
        //只要左边小于右边,那么它就一直分割下去
        if (left < right) {
            int middle = (left + right) / 2;
            //处理左边
            sort(arr, left, middle, temp);
            //处理右边
            sort(arr, middle + 1, right, temp);
            merge(arr, left, middle, right, temp);
        }
    }

    private static void merge(int[] arr, int left, int middle, int right, int[] temp) {
        int leftIndex = left;
        int rightIndex = middle + 1;
        int tempIndex = 0;
        while (leftIndex <= middle && rightIndex <= right) {
            if (arr[leftIndex] < arr[rightIndex]) {
                //那么就将arr[leftIndex]放入到临时数组,并且tempIndex以及leftIndex都往后移动一位
                temp[tempIndex++] = arr[leftIndex++];
            } else { //那么就将arr[rightIndex]放入到临时数组,并且tempIndex以及leftIndex都往后移动一位
                temp[tempIndex++] = arr[rightIndex++];
            }
        }

        //说明左边数据还没有处理完毕,继续处理
        while (leftIndex <= middle) {
            temp[tempIndex++] = arr[leftIndex++];
        }
        //说明右边数据还没有处理完毕,继续处理
        while (rightIndex <= right) {
            temp[tempIndex++] = arr[rightIndex++];
        }

        tempIndex = 0;
        int tempLeft = left;
        //此次排序完成,修改arr中的原始数据
        while (tempLeft <= right) {
            arr[tempLeft++] = temp[tempIndex++];
        }
    }


    public static void main(String[] args) {
        int[] arr = {9, 4, 6, 1, 5, 11};
        int[] temp = new int[arr.length];
        sort(arr, 0, arr.length - 1, temp);
        System.out.println(Arrays.toString(temp));

        int[] arrays = new int[80000000];
        for (int i = 0; i < 80000000; i++) {
            arrays[i] = (int) (Math.random() * 80000000);
        }

        //这种方式比下一种更快一些
        new Thread(() -> {
            long start = System.currentTimeMillis();
            int[] originArr = Arrays.copyOf(arrays, arrays.length);
            int[] temp2 = new int[originArr.length];
            sort(originArr, 0, originArr.length - 1, temp2);
            long end = System.currentTimeMillis();
            System.out.println("归并排序所花时间1::" + (end - start));
        }).start();

        //这种比上一种方式,多出频繁创建以及销毁数组的时间开销
        new Thread(() -> {
            long start = System.currentTimeMillis();
            MergeSort.sort(Arrays.copyOf(arrays, arrays.length));
            long end = System.currentTimeMillis();
            System.out.println("归并排序所花时间2::" + (end - start));
        }).start();


    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值