快速排序 - Qucik Sorting

1. 定义

快速排序是对冒泡排序的一种改进

1.1 性质

  • 交换排序
  • 不稳定

1.2 它的基本思想是

通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列

1.3 操作原理

  1. 从数列中挑出一个元素,称为“基准”(pivot)

  2. 重新排序数列,将比基准小的元素放在前边,比基准大的放在后边,相同的确定的选择任意一边都行,最后把pivot放在前边和后边的分解元素位上

  3. 如上1、2的操作叫一次partition 分区操作,接下来,递归的(recusive)将前边子数列和后边子数列排序

2. Java代码

一般来说,这个算法描述起来很容易让人理解,难度并不大。但是写出一个正确的无BUG的代码,确实不是一件容易的事

接下来,我尝试描述一个容易理解的Java版本

  1. 因为要递归调用,所以必然要把代码封装为一个单独的函数,而不可能直接写在mian函数中

    //因为要递归调用,也就是说需要传入子数列,所以需要留两个索引位来确定子数列left、right
    public static void quickSort(int[] array, int left, int right) {
        if (left < right) {//因为是递归调用,所以必须设计递归结束条件,这里即是:left < right
            int l = left, r = right;//left和right后边递归调用子数列时需要所以要留着,这样就需要复制两个来用l、r
            int key = array[left];//确定数列第l个为pivot
    
            //...
            //...
    
            //上边...代码操作完之后,最终会使l和r在pivot的索引位置碰面,也就是说l和r相等
            quickSort(array, left, l - 1);//递归左子数列
            quickSort(array, r + 1, right);//右
        }
    }
  2. 具体操作代码由2层嵌套while循环组成,
    先说外层while循环

    public static void quickSort(int[] array, int left, int right) {
        if (left < right) {
            int l = left, r = right;
            int key = array[left];
    
            //外层while循环条件为l < r来推动循环
            //且,通过里面的r--和l++操作就会使得l和r越来越接近,最终外层循环结束时应该有l=r
            while (l < r) {
                while (l < r && array[r] >= key) {
                    r--;
                }
                array[l] = array[r];
    
                while (l < r && array[l] <= key) {
                    l++;
                }
                array[r] = array[l];
            }
            array[l] = key;//外层循环结束时,将l或者r代表的元素赋值为pivot
    
            quickSort(array, left, l - 1);
            quickSort(array, r + 1, right);
        }
    }
  3. 接下来说内层while循环

    public static void quickSort(int[] array, int left, int right) {
        if (left < right) {
            int l = left, r = right;
            int key = array[left];
    
            while (l < r) {
    
                //内层2个while循环,控制从后往前、从前往后与pivot比较
    
                //while条件为:如果后面的元素 >=pivot 的话,那不会交换,而是对后索引 r 做 -- 操作
                //又因为不能让 -- 造成 l = r 的情况发生,所以要 l < r
                while (l < r && array[r] >= key) {
                    r--;
                }
                //当达到这里时,要么是1:array[r] < key情况,将后边元素放入前边已经复制过一份的元素的位置(要么是刚开始array[l]赋值给了key,要么是运行时array[l]赋值给了某个array[r])
                //要么是2:由于l=r了,这个赋值操作相当于什么都没发生
                array[l] = array[r];
    
                //这个如上,只不过是从前往后的
                while (l < r && array[l] <= key) {
                    l++;
                }
                array[r] = array[l];
            }
            array[l] = key;
    
            quickSort(array, left, l - 1);
            quickSort(array, r + 1, right);
        }
    }
  4. 如此,已经说完了,正式调用时,可能如下

    public static void main(String[] args) {
        int[] array = new int[] { 5, 4, 1, 0, -1, 1, 11, -11, 21 };
    
        quickSort(array, 0, array.length - 1);
    }

3. 时间复杂度

平均:T(n) = O(n log n);
最差:T(n) = O(n2)

求解过程,学了很久还没理解……之后补上

你可能感兴趣的:(java,递归,快速排序)