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

快速排序 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 ? true
low == high ? true
low == high ? true
low == high ? true
low == high ? true
low == high ? true
[1, 5, 7, 10, 14, 18, 19, 24, 24, 27]
------------------------
[12, 5, 6, 18, 27, 28, 27, 17, 23, 22]
low == high ? true
low == high ? true
low == high ? true
low == high ? true
low == high ? true
low == high ? true
low == high ? true
[5, 6, 12, 17, 18, 22, 23, 27, 27, 28]
------------------------
[17, 9, 4, 8, 19, 3, 29, 5, 29, 21]
low == high ? true
low == high ? true
low == high ? true
low == high ? true
low == high ? true
low == high ? true
[3, 4, 5, 8, 9, 17, 19, 21, 29, 29]
------------------------
[25, 25, 11, 19, 5, 2, 2, 13, 7, 15]
low == high ? true
low == high ? true
low == high ? true
low == high ? true
low == high ? true
low == high ? true
low == high ? true
[2, 2, 5, 7, 11, 13, 15, 19, 25, 25]
------------------------
[27, 2, 21, 20, 11, 2, 9, 21, 15, 29]
low == high ? true
low == high ? true
low == high ? true
low == high ? true
low == high ? true
low == high ? true
[2, 2, 9, 11, 15, 20, 21, 21, 27, 29]
------------------------
[10, 5, 14, 21, 27, 9, 11, 29, 4, 23]
low == high ? true
low == high ? true
low == high ? true
low == high ? true
low == high ? true
low == high ? true
[4, 5, 9, 10, 11, 14, 21, 23, 27, 29]
------------------------
[21, 22, 23, 8, 0, 26, 12, 5, 2, 24]
low == high ? true
low == high ? true
low == high ? true
low == high ? true
low == high ? true
low == high ? true
low == high ? true
[0, 2, 5, 8, 12, 21, 22, 23, 24, 26]
------------------------
[16, 25, 14, 19, 21, 27, 19, 1, 14, 6]
low == high ? true
low == high ? true
low == high ? true
low == high ? true
low == high ? true
low == high ? true
low == high ? true
[1, 6, 14, 14, 16, 19, 19, 21, 25, 27]
------------------------
[26, 3, 4, 26, 4, 20, 1, 26, 29, 25]
low == high ? true
low == high ? true
low == high ? true
low == high ? true
low == high ? true
low == high ? true
low == high ? true
[1, 3, 4, 4, 20, 25, 26, 26, 26, 29]
------------------------
[23, 5, 14, 8, 8, 5, 16, 14, 22, 29]
low == high ? true
low == high ? true
low == high ? true
low == high ? true
low == high ? true
low == high ? true
low == high ? true
[5, 5, 8, 8, 14, 14, 16, 22, 23, 29]

你可能感兴趣的:(java,数据结构,C++,c,快速排序)