快速排序+快速选择(常用于筛选前N个最大or最小)-java实现

快速排序+快速选择(常用于筛选前N个最大or最小)-java实现

最近这一两天,终于有空复习以前学习的东西了。前面忙着学SpringCloud和Netty感觉花费了太多时间,做项目也是。后来实习的面试准备就等于没准备,全靠着以前学习的记忆面试。果不其然,效果不是很好。
这里建议大家做项目量力而行,最好还是多学习和复习所学的知识。毕竟别人往往一两句话就认定了你的项目的水准和花费的努力。而复习所学的知识,反而才更适合现在的环境。

吐槽完毕,最近终于有时间做题了,重新复习了下快排。(毕竟用了很多次,所以写一写,当作复习了)

下面是java版本的快速排序快速选择

public Test{
    @Test
    public void testSort() {

        // 选择前11小的数字
        int[] arr1 = {10, 10, 10, 9, 9, 9, 8, 8, 8, 7, 7, 7, 6, 6, 6, 5, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 1, 1, 1};
        quickTopN(arr1, true, 0, arr1.length - 1, 10);
        System.out.println("选择前11小的数字");
        for (int item : arr1) {
            System.out.printf("%d ", item);
        }
        System.out.println();


        // 选择前11大的数字
        int[] arr2 = {1,1,1,2,2,2,3,3,3,4,4,4,5,5,5,6,6,6,7,7,7,8,8,8,9,9,9,10,10,10};
        quickTopN(arr2, false, 0, arr2.length - 1, 10);
        System.out.println("选择前11大的数字");
        for (int item : arr2) {
            System.out.printf("%d ", item);
        }
        System.out.println();


        // 快排,升序
        int[] arr3 = {1,9,3,4,7,6,2,4,8,1,5,2,6,5,2,4,7,5,1,3,6,9,5,1,3,4,7,1,2,8,3,5,8,2,4,2,1,5,7,6,2,1,4,6,9,2,4,7,1,3,5,8,1,2,6,6,2,1,7,1,2,6,4,8,1,3,5,7,1,2};
        quickSort(arr3, true, 0,arr3.length-1);
        System.out.println("快排,升序");
        for (int item : arr3) {
            System.out.printf("%d ", item);
        }
        System.out.println();

        // 快排,降序
        int[] arr4 = {4,5,7,1,3,5,2,1,9,3,4,1,2,5,8,71,2,1,5,4,1,3,9,5,1,2,5,4,7,2,3,3,1,5,4,8,6,2,4,7,1,6,1,2,5,4,3,9,2,4,2,2,7,6,1,36,5,4,8,2,1,3,5,7,1,54,2,2,81,3,5,7,21,6,5,2,78,2,4,5,9};
        quickSort(arr4, false, 0,arr4.length-1);
        System.out.println("快排,降序");
        for (int item : arr4) {
            System.out.printf("%d ", item);
        }
        System.out.println();


    }

    /**
     * TopN,快速选择(类快排)
     *
     * @param rawArr    原始数组
     * @param isAsc     是否升序,false则降序
     * @param start     需要筛选的闭区间的左边界
     * @param end       需要筛选的闭区间的右边界
     * @param targetEnd 需要得到的有序的闭区间的右边界
     * @apiNote 例如 rawArr=[1,6,4,2,3,5] isAsc=false, start=0 end=5, targetEnd=3,
     * 表示需要 得到长度6的数组rawArr的前4大的数字(0,1,2,3下标是4个数字)
     */
    public int[] quickTopN(int[] rawArr, boolean isAsc, int start, int end, int targetEnd) {
        int basePos = quickSelect(rawArr, isAsc, start, end);
        if (basePos == targetEnd) return rawArr;
        return basePos >= targetEnd ? quickTopN(rawArr, isAsc, start, basePos - 1, targetEnd) : quickTopN(rawArr, isAsc, basePos + 1, end, targetEnd);
    }

    /**
     * 快速排序
     * @param rawArr 需要快排的原始数组
     * @param isAsc 是否升序
     * @param start 需要快排的闭区间的左边界
     * @param end 需要快排的闭区间的右边界
     */
    public void quickSort(int[] rawArr, boolean isAsc,int start,int end) {
        int mid = quickSelect(rawArr, isAsc, start, end);
        if(start<mid)
            quickSort(rawArr,isAsc,start, mid-1);
        if(mid<end)
            quickSort(rawArr,isAsc,mid+1, end);

    }


    /**
     * 快速选择
     * @param rawArr 需要快速选择的原数组
     * @param isAsc 是否升序
     * @param start 需要快速选择的闭区间的左边界
     * @param end 需要快速选择的闭区间的右边界
     * @return 返回基准的下标
     */
    public int quickSelect(int[] rawArr, boolean isAsc, int start, int end) {
        int baseVal = rawArr[start];
        int left = start, right = end;
        while (left < right) {
            if (isAsc) {
                while (left < right && rawArr[right] >= baseVal)
                    --right;
                while (left < right && rawArr[left] <= baseVal)
                    ++left;

            } else {
                while (left < right && rawArr[right] <= baseVal)
                    --right;
                while (left < right && rawArr[left] >= baseVal)
                    ++left;
            }
            if(left<right){
                int tmp = rawArr[left];
                rawArr[left] = rawArr[right];
                rawArr[right] = tmp;
            }
        }
        rawArr[start] = rawArr[left];
        rawArr[left] = baseVal;
        return left;
    }
}

输出结果如下(最好自己复制代码试试)

选择前11小的数字
1 1 1 2 2 2 3 3 3 4 4 7 6 6 6 5 5 5 4 7 7 8 8 8 9 9 9 10 10 10 
选择前11大的数字
10 10 10 9 9 9 8 8 8 7 7 4 5 5 5 6 6 6 7 4 4 3 3 3 2 2 2 1 1 1 
快排,升序
1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 8 8 8 8 8 9 9 9 
快排,降序
81 78 71 54 36 21 9 9 9 9 8 8 8 7 7 7 7 7 7 6 6 6 6 5 5 5 5 5 5 5 5 5 5 5 5 5 4 4 4 4 4 4 4 4 4 4 3 3 3 3 3 3 3 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 

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