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

概述

 在前面说到了两个关于交换排序的算法:冒泡排序与奇偶排序。

 本文就来说说交换排序的最后一拍:快速排序算法。之所以说它是快速的原因,不是因为它比其他的排序算法都要快。而是从实践中证明了快速排序在平均性能上的确是比其他算法要快一些,不然快速一说岂不是在乱说?

 本文就其原理、过程及实现几个方面讲解一下快速排序算法。


版权声明

著作权归作者所有。

商业转载请联系作者获得授权,非商业转载请注明出处。

作者:Coding-Naga

发表日期:2016年3月1日

链接:http://blog.csdn.net/lemon_tree12138/article/details/50622744

来源:CSDN

更多内容:分类 >> 算法与数学


目录

  • 概述
  • 版权声明
  • 目录
  • 快速排序
    • 算法原理

      • 原理分析
      • 原理图
    • 算法步骤
      • 步骤
      • 过程演示图
    • 逻辑实现
    • 复杂度分析
    • 番外
  • Ref
  • GitHub源码下载

快速排序

算法原理

原理分析

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

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

原理图


算法步骤

步骤

  1. 获得待排序数组a
  2. 选取一个合适的数字p(一般来说就选取数组或是子数组的第一个元素)作为排序基准
  3. 将待排序数组a中比基准p小的放在p的左边,比基准p大的放在p的右边

  4. 从第3步获得的两个子数组sub1跟sub2
  5. 判断sub1或sub2中是否只有一个元素,如果只有一个元素则返回此元素,否则就将sub1(或是sub2)代回到第1步中继续执行
  6. 具体过程可以参见下面的过程图

过程演示图


逻辑实现

/*
     * 排序的核心算法
     *
     * @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(n2)。

 如果我们在选取基准p的时候,每次选取的都是当前数组中最中间的一个元素(是中位数,而不是元素位置上的中间),那么每次划分都把当前数组划分成了长度相等的两个子数组,这样一来复杂度变成了O(nlog2n)。


番外

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

Ref

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

GitHub源码下载

https://github.com/William-Hai/ArraySortAlgorithm/blob/master/src/org/algorithm/array/sort/impl/QuickSort.java


时间: 2024-10-08 20:04:29

排序算法系列:快速排序算法的相关文章

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

记录学习点滴 快速排序算法是一种很有趣的算法,短小精悍,性能强劲,对于大部分情况都可以胜任,但对极端环境难以应付. 快速排序我理解为:这是一个“以自我为中心的”+“分治法”思想的算法. 分治法不必多说,化繁为简,那就是逐个击破. 那什么是“以自我为中心”?顾名思义,就是每次都一个“我”,每个人都要围绕“我”行事,比“我”小的都去左边站着,比“我”他大的都去右边站着,而且“我”不去关心每一边都有谁,反正你没“我”大或者小就行.一旦“我”落位了妥帖了,“我”就不动了.然后再在左右两边分别产生新“我”

c#冒泡排序算法和快速排序算法

依次比较相邻的两个数,将小数放在前面,大数放在后面. 第1趟: 首先比较第1个和第2个数,将小数放前,大数放后.然后比较第2个数和第3个数,将小数放前,大数放后,如此继续,直至比较最后两个数,将小数放前,大数放后.至此第一趟结束,将最大的数放到了最后. 第2趟: 仍从第一对数开始比较(因为可能由于第2个数和第3个数的交换,使得第1个数不再小于第2个数),将小数放前,大数放后,一直比较到倒数第二个数(倒数第一的位置上已经是最大的),第二趟结束,在倒数第二的位置上得到一个新的最大数(其实在整个数列中

优化算法系列-模拟退火算法(1)——0-1背包问题

优化算法系列之模拟退火算法(1)--0-1背包问题 1问题描述 有一个窃贼在偷窃一家商店时发现有N件商品:第i件物品价值vi元,重wi磅,其中vi.wi都是整数.他希望带走的东西越值钱越好,但他的背包小,最多只能装下W磅的东西(W为整数).如果每件物品或被带走或被留下,小偷应该带走哪几件东西? 2解空间 设xi表示第i件物品的取舍,1代表取,0代表舍,搜索空间为n元一维数组(x1,x2,x3,.....,xn).因而解空间的取值范围可表示为(0,0,0,....,0),(0,0,0,......

希尔排序算法和快速排序算法

希尔排序源代码如下: #include <stdio.h> //希尔排序 void shellSort(int a[],int l, int r){ //一次排序同一步长所组成的集合 如a[0],a[5],a[10]... int i,j,h; for(h=1;h<=(r-1)/9;h=3*h+1); //设置步长为1,4,13,40,121,...序列 for( ; h>0;h/=3) for(i=h;i<=r;i++){ int j = i;int v = a[i]; w

iOS算法(一)快速排序算法

快速排序是当遇到较大数据时,排序快,高效的方法(公司面试时,基本上会被问到...) 该方法的基本思想是: 1.先从数列中取出一个数作为基准数. 2.分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边. 3.再对左右区间重复第二步,直到各区间只有一个数. 简单地理解就是,找一个基准数(待排序的任意数,一般都是选定首元素),把比小于等于基准数的元素放到基准数的左边,把大于基准数的元素放在基准数的右边.排完之后,在把基准数的左边和右边各看成一个整体,  左边:继续选择基准数把小于

[算法研究]の快速排序算法--javascript实现

快速排序(Quicksort)是对冒泡排序的一种改进. 快速排序由C. A. R. Hoare在1962年提出.它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列. 时间复杂度最坏的情况下是O(nlogn) .也是相似复杂度下较常用的一种排序 var s = [72 ,6, 57, 88, 60, 42, 83 ,73, 48,57,

搞定面试算法系列 —— 分治算法三步走

主要思想 分治算法,即分而治之:把一个复杂问题分成两个或更多的相同或相似子问题,直到最后子问题可以简单地直接求解,最后将子问题的解合并为原问题的解. 归并排序就是一个典型的分治算法. 三步走 和把大象塞进冰箱一样,分治算法只要遵循三个步骤即可:分解 -> 解决 -> 合并. 分解:分解原问题为结构相同的子问题(即寻找子问题) 解决:当分解到容易求解的边界后,进行递归求解 合并:将子问题的解合并成原问题的解 这么一说似乎还是有点抽象?那我们通过经典的排序算法归并排序来体验一下分治算法的核心思想.

基础算法之快速排序算法

快速排序基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列. 比如序列[6,8,1,4,3,9],选取6为基准数key(不会变的),然后从右往左遍历过去,发现第一个比key小的数3,就把6和3交换位置,序列就变成了[3,8,1,4,6,9] 然后从左往右遍历过去,发现第一个比key大的值8,把8和6交换位置,序列变成[3,6,1,4,8,

【经典算法】快速排序算法

原文地址:http://blog.csdn.net/morewindows/article/details/6684558 作者:MoreWindows 快速排序由于排序效率在同为O(N*logN)的几种排序方法中效率较高,因此经常被采用,再加上快速排序思想----分治法也确实实用,因此很多软件公司的笔试面试,包括像腾讯,微软等知名IT公司都喜欢考这个,还有大大小的程序方面的考试如软考,考研中也常常出现快速排序的身影.总的说来,要直接默写出快速排序还是有一定难度的,因为本人就自己的理解对快速排序

排序算法之 Java简单快速排序算法

package net.qh.test.sort; import java.util.ArrayList; import java.util.Calendar; import java.util.List; /** * Created by Administrator on 2016/03/01. */ public class SimpleQuick { public int[] sort(int[] arr,int left,int right){ if ( arr == null || a