排序算法系列:快速排序算法

概述

在前面说到了两个关于交换排序的算法:冒泡排序与奇偶排序。
 本文就来说说交换排序的最后一拍:快速排序算法。之所以说它是快速的原因,不是因为它比其他的排序算法都要快。而是从实践中证明了快速排序在平均性能上的确是比其他算法要快一些,不然快速一说岂不是在乱说?
 本文就其原理、过程及实现几个方面讲解一下快速排序算法。


版权声明

著作权归作者所有。
商业转载请联系作者获得授权,非商业转载请注明出处。
作者:Q-WHai
发表日期:2016年3月1日
链接:https://qwhai.blog.csdn.net/article/details/50622744
来源:CSDN
更多内容:分类 >> 算法与数学


目录

文章目录

  • 概述
  • 版权声明
  • 目录
  • 快速排序
    • 算法原理
      • 原理分析
      • 原理图
    • 算法步骤
      • 步骤
      • 过程演示图
    • 逻辑实现
    • 复杂度分析
    • 番外
  • Ref
  • GitHub源码下载

快速排序

算法原理

原理分析

快速排序(Quicksort)是对冒泡排序的一种改进。

快速排序由C. A. R. Hoare在1962年提出。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

原理图

排序算法系列:快速排序算法_第1张图片


算法步骤

步骤

  1. 获得待排序数组a
  2. 选取一个合适的数字p(一般来说就选取数组或是子数组的第一个元素)作为排序基准
  3. 将待排序数组a中比基准p小的放在p的左边,比基准p大的放在p的右边
    这里写图片描述
  4. 从第3步获得的两个子数组sub1跟sub2
  5. 判断sub1或sub2中是否只有一个元素,如果只有一个元素则返回此元素,否则就将sub1(或是sub2)代回到第1步中继续执行
  6. 具体过程可以参见下面的过程图

过程演示图

排序算法系列:快速排序算法_第2张图片


逻辑实现

/*
     * 排序的核心算法
     * 
     * @param array
     *      待排序数组
     * @param startIndex
     *      开始位置
     * @param endIndex
     *      结束位置
     */
    private void sortCore(int[] array, int startIndex, int endIndex) {
        if (startIndex >= endIndex) {
            return;
        }
        
        int boundary = boundary(array, startIndex, endIndex);
        
        sortCore(array, startIndex, boundary - 1);
        sortCore(array, boundary + 1, endIndex);
    }
    
    /*
     * 交换并返回分界点
     * 
     * @param array
     *      待排序数组
     * @param startIndex
     *      开始位置
     * @param endIndex
     *      结束位置
     * @return
     *      分界点
     */
    private int boundary(int[] array, int startIndex, int endIndex) {
        int standard = array[startIndex]; // 定义标准
        int leftIndex = startIndex; // 左指针
        int rightIndex = endIndex; // 右指针
        
        while(leftIndex < rightIndex) {
            while(leftIndex < rightIndex && array[rightIndex] >= standard) {
                rightIndex--;
            }
            array[leftIndex] = array[rightIndex];
            
            while(leftIndex < rightIndex && array[leftIndex] <= standard) {
                leftIndex++;
            }
            array[rightIndex] = array[leftIndex];
        }
        
        array[leftIndex] = standard;
        return leftIndex;
    }

复杂度分析

排序方法 时间复杂度 空间复杂度 稳定性 复杂性
平均情况 最坏情况 最好情况
快速排序 O(nlog2n) O(n2) O(nlog2n) O(log2n) 不稳定 较复杂

 这里我们可以做一些关于复杂度的推理。  如果我们在选取基准p的时候,每次选取的都是当前数组中最小的一个元素,那么每次划分都只是让数组中的元素少1(被筛选出来的那个元素当然有序),这样一来就需要反复遍历数组导致复杂度变成了O(n 2)。  如果我们在选取基准p的时候,每次选取的都是当前数组中最中间的一个元素(是中位数,而不是元素位置上的中间),那么每次划分都把当前数组划分成了长度相等的两个子数组,这样一来复杂度变成了O(nlog 2n)。

番外

  1. 对于基准元素的选取,也可以采用随机数选取的方式
  2. 如果要按照元素在位置上的中间来选取基准元素,还可以将中间位置上的元素与第一个元素进行对换

Ref

  • 《算法导论 (第3版)》
  • 《编程珠玑 (第2版)》

GitHub源码下载

  • https://github.com/qwhai/algorithms-sort

你可能感兴趣的:(算法与数学)