数据结构基础 —— 快速排序 java 实现

来源:互联网 发布:芜湖编程招聘 编辑:程序博客网 时间:2024/05/21 10:15

快速排序 java 实现

一种代码

下面的这个 if (last > first) 一定要加

    private static void quickSort(Integer[] data, int first, int last) {        if (last > first) {            int pivotIndex = partion(data, first, last);            quickSort(data, first, pivotIndex-1);            quickSort(data, pivotIndex+1, last);        }    }

下面这个程序是讲 list 的 first 到 last 的元素分为两组,一组小于 pivot,一组大于 pivot。注意,组内的元素并不一定有序,所以需要递归调用,知道first == last,也就是最后只剩一个元素。

这儿我们选择第一个元素作为 pivot
这儿的思路是low 从左往右,high 从右往左
low 找到>pivot, high 找到小于

    /**     *      * @param list     *            数组     * @param first     *            第一个元素     * @param last     *            最后一个元素(包含)     * @return     */    private static int partion(Integer[] list, int first, int last) {        int pivot = list[first];        int low = first + 1;        int high = last;        System.out.println("待分组的序列: "+Arrays.toString(Arrays.copyOfRange(list, first, last+1)));        while (low < high) {            // low <= high should be placed before list[low] <= pivot            // otherwise it may cause ArrayIndexOutOfBoundsException            // 改成 low < high 两个条件的顺序不重要了?这时候最多 low == high            // 不会存在 low == high+1,超出范围            while (low < high  && list[low] <= pivot ) {                low++;            }            // 这儿倒是谁前谁后不重要,因为low<high最多就是 low == high            // 当 low == high 时,循环结束,不存在 high 会为-1情况            while (list[high] >= pivot && low < high) {                high--;            }            /**             * 交换这两个元素             */            if (low < high) {                int temp = list[low];                list[low] = list[high];                list[high] = temp;            }        }        /**         * 找到小于 pivot 的锚点,找出最后的返回值         * high > first 是防止数组越界的         * 这时候的数据 是一部分小于pivot,一部分大于 pivot         * 本函数从高往低走,找出         */        while (high > first && list[high] >= pivot) {            high--;        }        // 只可能是 pivot == list[high] 或者 >        //得到的 high 值是小于 pivot 区域的最后一个数        //这儿交换两个数的位置        if (pivot > list[high]) {            list[first] = list[high];            list[high] = pivot;            System.out.print(Arrays.toString(Arrays.copyOfRange(list, first, high)));            System.out.print(" [ pivot=" + list[high] + " ] ");            if (high + 1 <= last)                System.out.print(Arrays.toString(Arrays.copyOfRange(list, high + 1, last + 1)));            else {                System.out.print(" []");            }            System.out.println();            return high;        } else {            //这种情况是 pivot 是最小值,其他数都在它右边            System.out.println("high=" + high + " list[high]=" + list[high]);            System.out.print("[ pivot=" + list[first] + " ]");            System.out.println(Arrays.toString(Arrays.copyOfRange(list, first + 1, last + 1)));            return high;        }    }    public static void shellPass(Integer[] array, int d) {        for (int i = d; i < array.length; i++) {            int temp = array[i];            int j = i - d;            while (j >= 0 && array[j] > temp) {                array[j + d] = array[j];                j -= d;            }            array[j + d] = temp;        }    }

测试输出

public static void main(String[] args) {        Random r = new Random();        Integer[] data = new Integer[10];        for (int ii = 0; ii < 10; ii++) {            for (int i = 0; i < data.length; i++) {                data[i] = r.nextInt(30);            }            System.out.println("------------------------");            System.out.println(Arrays.toString(data));            quickSort(data, 0, data.length - 1);            System.out.println(Arrays.toString(data));        }    }

输出

------------------------[29, 15, 2, 15, 10, 0, 2, 14, 29, 17]待分组的序列: [29, 15, 2, 15, 10, 0, 2, 14, 29, 17][17, 15, 2, 15, 10, 0, 2, 14, 29] [ pivot=29 ]  []待分组的序列: [17, 15, 2, 15, 10, 0, 2, 14, 29][14, 15, 2, 15, 10, 0, 2] [ pivot=17 ] [29]待分组的序列: [14, 15, 2, 15, 10, 0, 2][10, 2, 2, 0] [ pivot=14 ] [15, 15]待分组的序列: [10, 2, 2, 0][0, 2, 2] [ pivot=10 ]  []待分组的序列: [0, 2, 2]high=0 list[high]=0[ pivot=0 ][2, 2]待分组的序列: [2, 2]high=1 list[high]=2[ pivot=2 ][2]待分组的序列: [15, 15]high=5 list[high]=15[ pivot=15 ][15][0, 2, 2, 10, 14, 15, 15, 17, 29, 29]

改进

选取线性表的第一个元素作为主元。
理想情况下是 主元可以把一组数据分为相同个数的两部分

改进简单方法是,选取第一个元素、中间元素、最后一个元素作为主元。

对于有序序列采用快排是个灾难,因为选取第一个元素作为主元,会使得一边空,一边是剩下的元素。
这样递归的次数比两边个数均等时候更多

第二种划分算法

    private static int partion2(Integer[] list, int low, int high) {        int pivot = list[low];        while (low < high) {            while (low < high && list[high] >= pivot)                high--;            if (low < high)                 list[low++]=list[high];            while (low < high && list[low] <= pivot)                 low++;            if (low < high)                list[high--] = list[low];        }        //while循环结束肯定 low == high        System.out.println("low == high ? " + (low == high));        list[low] = pivot;        return low;    }

上面这个方法很简洁,利用了 pivot = list[low],多了一个冗余的数组位置。所以,先从 high 从右往左,把小于 pivot 的元素放在 low 处,list[low++]=list[high];这儿 low+1,再从左往右。刚才的list[high]元素也有两个值,可以把大于 pivot 的元素放在 list[high--] = list[low]处、

测试 partion2

输出

------------------------[27, 18, 5, 19, 24, 10, 1, 24, 14, 7]low == high ? truelow == high ? truelow == high ? truelow == high ? truelow == high ? truelow == high ? true[1, 5, 7, 10, 14, 18, 19, 24, 24, 27]------------------------[12, 5, 6, 18, 27, 28, 27, 17, 23, 22]low == high ? truelow == high ? truelow == high ? truelow == high ? truelow == high ? truelow == high ? truelow == high ? true[5, 6, 12, 17, 18, 22, 23, 27, 27, 28]------------------------[17, 9, 4, 8, 19, 3, 29, 5, 29, 21]low == high ? truelow == high ? truelow == high ? truelow == high ? truelow == high ? truelow == high ? true[3, 4, 5, 8, 9, 17, 19, 21, 29, 29]------------------------[25, 25, 11, 19, 5, 2, 2, 13, 7, 15]low == high ? truelow == high ? truelow == high ? truelow == high ? truelow == high ? truelow == high ? truelow == high ? true[2, 2, 5, 7, 11, 13, 15, 19, 25, 25]------------------------[27, 2, 21, 20, 11, 2, 9, 21, 15, 29]low == high ? truelow == high ? truelow == high ? truelow == high ? truelow == high ? truelow == high ? true[2, 2, 9, 11, 15, 20, 21, 21, 27, 29]------------------------[10, 5, 14, 21, 27, 9, 11, 29, 4, 23]low == high ? truelow == high ? truelow == high ? truelow == high ? truelow == high ? truelow == high ? true[4, 5, 9, 10, 11, 14, 21, 23, 27, 29]------------------------[21, 22, 23, 8, 0, 26, 12, 5, 2, 24]low == high ? truelow == high ? truelow == high ? truelow == high ? truelow == high ? truelow == high ? truelow == high ? true[0, 2, 5, 8, 12, 21, 22, 23, 24, 26]------------------------[16, 25, 14, 19, 21, 27, 19, 1, 14, 6]low == high ? truelow == high ? truelow == high ? truelow == high ? truelow == high ? truelow == high ? truelow == high ? true[1, 6, 14, 14, 16, 19, 19, 21, 25, 27]------------------------[26, 3, 4, 26, 4, 20, 1, 26, 29, 25]low == high ? truelow == high ? truelow == high ? truelow == high ? truelow == high ? truelow == high ? truelow == high ? true[1, 3, 4, 4, 20, 25, 26, 26, 26, 29]------------------------[23, 5, 14, 8, 8, 5, 16, 14, 22, 29]low == high ? truelow == high ? truelow == high ? truelow == high ? truelow == high ? truelow == high ? truelow == high ? true[5, 5, 8, 8, 14, 14, 16, 22, 23, 29]
0 0