详解快速排序算法(Java版)

 ̄綄美尐妖づ 提交于 2019-12-21 19:18:46

前言

快速排序(Quick Sort)算法和冒泡排序算法类似,都是基于交换排序的思想。快速排序算法对冒泡排序算法进行了改进,从而具有更高的执行效率。而且也是面试常考的一种算法,不仅得会写,更主要的是理解其中的思想。

快速排序的流程

(1)首先设定一个分界值,通过该分界值将数组分为左右两部分
(2)将大于等于分界值的数据集中到数组的右边,小于分界值的数据集中到数组的左边,此时左边部分中各元素都小于等于分界值,右边部分中各元素都大于分界值
(3)然后,左边和右边的数据可以独立排序。对于左侧的数组数据,又可以取一个分界值,将该部分数据分成左右两部分,同样将左边放置较小值,右边放置较大值。右侧的数组也做类似处理。
(4)重复上述过程,可以看出,这是一个递归定义。通过递归将左侧部分排好后,再递归排好右侧部分的顺序。当左、右两部分各数据排序完成后,整个数组的排序也就完成了

详细代码

上面的流程,一般看完后会懵懵懂懂,结合下面的代码,然后慢慢理解

public class MyQuickSort {
    static final int SIZE = 18;

    /**
     * @param arr   待排序的数组
     * @param left  数组的左边界(例如,从起始位置开始排序,则left=0)
     * @param right 数组的右边界(例如,排序截至到数组末尾,则right=arr.length-1)
     */
    private static void quickSort(int[] arr, int left, int right) {
        int f, t;//f是分界值,t是后面要进行交换的临时temp变量
        int rtemp, ltemp;//左、右数组临时变量
        ltemp = left;//由于要一直移动指针(索引),因此要定义左右两侧的临时指针(索引)变量
        rtemp = right;
        f = arr[(left + right) / 2];//分界值
        while (ltemp < rtemp) { //确保左边的索引要小于右边(因为我们左边放比分界值小的值,右边放比分界值大的值)
            //只有等左边的值小于分界值,我们的指针才会继续向右移动,
            // 否则,指针就指这个值,等待和右边的值交换
            while (arr[ltemp] < f) {
                ++ltemp; // 指针向右移动
            }
            //只有等右边的值大于于分界值,我们的指针才会继续向左移动,
            // 否则,指针就指这个值,等待和左边的值交换
            while (arr[rtemp] > f) {
                --rtemp;// 指针向左移动
            }
            //程序走早这里,一定是出现,左侧指针指向了大于分界值的数据,右侧指针指向了小于分界值的数据
            if (ltemp <= rtemp) { // 依然是确保左边的索引要小于右边(因为我们左边放比分界值小的值,右边放比分界值大的值)
                //交换两个数据,也就是把右边小于分界值的数据和左边大于分界值的数据进行交换,
                // 这样就可以做到左边永远都小于分界值,右边永远都大于分界值
                t = arr[ltemp];
                arr[ltemp] = arr[rtemp];
                arr[rtemp] = t;
                ++ltemp;//交换完后,左侧的指针向右侧移动一位
                --rtemp; //交换完后,右侧的指针向左侧移动一位
            }
        }
      
        if (ltemp == rtemp) {
            ltemp++;
        }
        //确保右侧的指针向左移动不能超过数组左侧索引
        if (left < rtemp) {
            //此时left依然不变,而right的位置已经变为ltemp-1
            quickSort(arr, left, ltemp - 1);//递归调用
        }
        //确保左侧的指针向右移动不能超过数组右侧索引
        if (ltemp < right) {
            //此时right依然不变,而left的位置已经变为rtemp+1
            quickSort(arr, rtemp + 1, right);//递归调用
        }
    }

    public static void main(String[] args) {
        int[] arr = new int[SIZE];
        int i;
        for (i = 0; i < SIZE; i++) {
            arr[i] = (int) (100 + Math.random() * (100 + 1));//初始化数组
        }
        System.out.print("排序前的数组为:\n");
        for (i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + " ");
        }
        System.out.println();
        quickSort(arr, 0, arr.length - 1);//排序操作;
        System.out.print("排序后数组为:\n");
        for (i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + " "); //输出排序后的数组
        }
        System.out.println();
    }
}

运行结果:

排序前的数组为:
131 167 177 163 120 110 109 158 161 190 102 148 193 188 120 169 140 169 
排序后数组为:
102 109 110 120 120 131 140 148 158 190 161 163 167 169 169 177 188 193 

后记

一定要理解什么情况下左侧需要和右侧数据进行交换

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!