本文作者华科小涛:@http://www.cnblogs.com/hust-ghtao/,参考《算法导论》,代码借用《剑指offer》

快速排序是一种最坏情况时间复杂度为的排序算法。虽然最坏情况的时间复杂度很差,在在实际应用中是最好的选择,平均性能很好:期望时间复杂度,而且隐含的常数因子非常小。另外,它还能够进行原排序,在虚拟环境中也能很好工作。基于随机抽样的快速排序算法,在输入元素互异的情况下,期望运行时间为。

1.基本思想

快速排序利用了分治策略。分治策略可以分为3个步骤:

  • 分解:将问题划分为一些子问题,子问题的形式与原问题一样,只是规模更小。
  • 解决:递归的求解出子问题。如果子问题的规模足够小,则停止递归,直接求解。
  • 合并:将子问题的解组合成原问题的解。

对一个典型的子数组A[p..r]进行快速排序的分治过程如下:

  • 分解:数组A[p..r]被划分为两个(可能为空)子数组A[p..q-1]和A[q+1..r],使得A[p..q-1]中的每一个元素都小于等于A[q],而A[q+1..r]中的每个元素都大于A[q]。其中计算下标q也是划分过程的一部分。
  • 解决:通过递归调用快速排序,对子数组A[p..q-1]和A[q+1..r]进行排序。
  • 合并:因为子数组都是原址排序的,所以不需要合并操作。

2.详细过程

快速排序的伪代码如下:

,为了排序数组A的全部元素,初始调用QUICKSORT(A, 1, A.length)。

其中最关键的部分就是数组的划分PARTITION,它实现了对子数组A[p..r]的原址重排。伪代码如下:

。

这里的PARTITION程序选择x=A[r]作为主元,并围绕着它来划分数组。

随着程序的增加,数组被划分成4个区域,如下图所示:

其中:

  • A[p..i]上的所有值都小于等于x;
  • A[i+1..j-1]区间的所有值都大于x;
  • A[j..r-1]是还未扫描的元素,可能属于任何一种情况;
  • A[r]=x。

指针 i 一直指向小值数组的最后一个元素,j指向大值数组末尾的下一个元素。

PARTITION的一次迭代过程中会出现两种情况:

(a)如果A[j]>x,需要做的只是将j值加1:

(b)A[j]<=x,则将i值加1,并交换A[i]和A[j],在将j值加1,使循环不变量保持不变。

。

在PARTITION的最后,将主元与最左的大于x的元素进行交换,就可以将主元移动到它在数组中的正确位置,并返回主元的新下标。

3.性能分析

快速排序的运行时间依赖于划分是否平衡,而平衡与否又依赖于用于划分的元素。

3.1 最坏情况划分

当划分产生的两个子问题分别包含了n-1个元素和0个元素,这是极不平衡的划分。假设算法的每一次递归都出现了这种不平衡的划分,算法运行时间的递归式可以表示为:

可以解得:。

所以,如果在算法的每一层递归上,划分都是最大程度不平衡的,那么算法的时间复杂度为:。

3.2 平均情况

在最平衡的划分中,PARTITION得到的两个子问题的规模都不大于n/2。算法运行时间的递归式为:

可以解得:

。

另外,只要是划分是常数比例的,甚至好的和差(极不平衡)的划分交替出现时,快速排序算法和全是好的划分时一样,仍然是。

4.随机化版本

在算法中引入随机性,使得算法对所有的输入都能获得较好的期望性能。

从A[p..r]中随机选择一个元素作为主元。为了达到这一目的,首先将A[r]与从A[p..r]随机选择的元素交换。通过对序列p..r随机抽样保证主元素

x=A[r]是等概率从r-p+1个元素中选取的。

下面是RANDOMIZED-PARTITION和RANDOMIZED-QUICKSORT的伪代码:

在使用RANDOMIZED-PARTITION,输入元素互异的情况下,快速排序算法的期望运行时间为。

6.代码实现

RANDOMIZED-PARTITION:

   1: int Partition(int data[], int length, int start, int end)  

   2: {  

   3:     if (data == NULL||length<=0||start<0||end>=length)  

   4:     {  

   5:         throw new std::exception("Invalid Parameters");  

   6:     }  

   7:     int index = RandomInRange(start, end);  

   8:     Swap(&data[index], &data[end]);  

   9:   

  10:     int small = start - 1;  

  11:     for (index = start; index < end;++index)  

  12:     {  

  13:         if (data[index] < data[end])  

  14:         {  

  15:             ++small;  

  16:             if (small!=index)  

  17:             {  

  18:                 Swap(&data[index], &data[small]);  

  19:             }  

  20:         }  

  21:     }  

  22:     ++small;  

  23:     Swap(&data[small], &data[end]);  

  24:   

  25:     return small;  

  26: }  

QUICKSORT:

   1: void QuickSort(int data[], int length, int start, int end)  

   2: {  

   3:     if (start == end)  

   4:     {  

   5:         return;  

   6:     }  

   7:     int index = Partition(data, length, start, end);  

   8:     if (index >start)  

   9:     {  

  10:         QuickSort(data, length, start, index-1);  

  11:     }  

  12:     if (index<end)  

  13:     {  

  14:         QuickSort(data, length, index + 1, end);  

  15:     }  

  16: }  

快速排序原理、复杂度分析及C语言实现的更多相关文章

  1. 八大排序算法——快速排序(动图演示 思路分析 实例代码Java 复杂度分析)

    一.动图演示 二.思路分析 快速排序的思想就是,选一个数作为基数(这里我选的是第一个数),大于这个基数的放到右边,小于这个基数的放到左边,等于这个基数的数可以放到左边或右边,看自己习惯,这里我是放到了 ...

  2. 杨辉三角(Pascal Triangle)的几种C语言实现及其复杂度分析

    说明 本文给出杨辉三角的几种C语言实现,并简要分析典型方法的复杂度. 本文假定读者具备二项式定理.排列组合.求和等方面的数学知识. 一  基本概念 杨辉三角,又称贾宪三角.帕斯卡三角,是二项式系数在三 ...

  3. 数据结构( Pyhon 语言描述 ) — — 第3章:搜索、排序和复杂度分析

    评估算法的性能 评价标准 正确性 可读性和易维护性 运行时间性能 空间性能(内存) 度量算法的运行时间 示例 """ Print the running times fo ...

  4. 基于python语言使用余弦相似性算法进行文本相似度分析

    编写此脚本的目的: 本人从事软件测试工作,近两年发现项目成员总会提出一些内容相似的问题,导致开发抱怨.一开始想搜索一下是否有此类工具能支持查重的工作,但并没找到,因此写了这个工具.通过从纸上谈兵到着手 ...

  5. PHP函数的实现原理及性能分析

    前言 在任何语言中,函数都是最基本的组成单元.对于php的函数,它具有哪些特点?函数调用是怎么实现的?php函数的性能如何,有什么使用建议?本文将从原理出发进行分析结合实际的性能测试尝试对这些问题进行 ...

  6. 快速排序原理及Java实现

    1.基本思想: 快速排序是我们之前学习的冒泡排序的升级,他们都属于交换类排序,都是采用不断的比较和移动来实现排序的.快速排序是一种非常高效的排序算法,它的实现,增大了记录的比较和移动的距离,将关键字较 ...

  7. PHP 基础系列(三) 【转】PHP 函数实现原理及性能分析

    作者:HDK (百度) 前言 在任何语言中,函数都是最基本的组成单元.对于PHP的函数,它具有哪些特点?函数调用是怎么实现的?php函数的性能如何,有什么使用建议?本文将从原理出发进行分析结合实际的性 ...

  8. (转)PHP 函数的实现原理及性能分析

    前言 任何语言中,函数都是最基本的组成单元.对于php的函数,它具有哪些特点?函数调用是怎么实现的?php函数的性能如何,有什么使用建议?本文 将从原理出发进行分析结合实际的性能测试尝试对这些问题进行 ...

  9. 重拾算法之复杂度分析(大O表示法)

    .katex { display: block; text-align: center; white-space: nowrap; } .katex-display > .katex > ...

随机推荐

  1. junit4笔记

    这两天在复习hibernate,看的小峰的视频,觉得很不错. 现在把里面的junit4的一些使用方法记下来.方便以后的差用.代码如下. package com.java1234.service; im ...

  2. DDL 和DML 区别

    DML(Data Manipulation Language)数据操纵语言: 适用范围:对数据库中的数据进行一些简单操作,如insert,delete,update,select等. DDL(Data ...

  3. centos下yum安装crontab+mysql自动备份

    参考博文: centos下yum安装crontab yum install vixie-cron crontabs      //安装 chkconfig crond on               ...

  4. 使用阿里云集成包快速搭建LAMP+FTP教程

    LAMP集成包安装步骤 1.下载开发集成包 下载最新版的阿里云市场提供的WEB开发集成包(内含Apache.Mysql.PHP.vsftpd) #Linux指令wget http://gongdan. ...

  5. javascript复制

    1.实现点击按钮,复制文本框中的的内容 1 <scrip type="text/javascript"> 2 function copyUrl2() 3 { 4 var ...

  6. JAVA学习中好网站 - -

    http://www.54bk.com 我是博客 http://www.java-cn.com java中文网 http://java.sun.com sun官方网站 http://www.comej ...

  7. linux mount挂载设备(u盘,光盘,iso等 )使用说明

    对于新手学习,mount 命令,一定会有很多疑问.其实我想疑问来源更多的是对linux系统本身特殊性了解问题. linux是基于文件系统,所有的设备都会对应于:/dev/下面的设备.如: [cheng ...

  8. 用Chart控件绘制动态图表

    进行程序设计时,选用一个合适的ActiveX控件,有时可大大减少编程工作量.ActiveX 控件(又称OCX)基于COM技术,作为独立的软件模块,它可以在任何程序设计语言中插入使用.本文仅以VC++为 ...

  9. HDU 1150:Machine Schedule(二分匹配,匈牙利算法)

    Machine Schedule Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) ...

  10. 构件图(Component Diagram)—UML图(八)

    构件图是显示代码自身结构的实现级别的图表.构件图由诸如源码文件.二进制代码文件.可运行文件或动态链接库 (DLL) 这种构件构成,并通过依赖关系相连接 以下这张图介绍了构件图的基本内容: 以下这张图是 ...