一.快速排序算法的优点,为什么称之为快排?

Quicksort是对归并排序算法的优化,继承了归并排序的优点,同样应用了分治思想。

所谓的分治思想就是对一个问题“分而治之”,用分治思想来解决问题需要两个步骤:

1.如何“分”?(如何缩小问题的规模)

2.如何“治”?(如何解决子问题)

快排的前身是归并,而正是因为归并存在不可忽视的缺点,才产生了快排。归并的最大问题是需要额外的存储空间,并且由于合并过程不确定,致使每个元素在序列中的最终位置上不可预知的。针对这一点,快速排序提出了新的思路:把更多的时间用在“分”上,而把较少的时间用在“治”上。从而解决了额外存储空间的问题,并提升了算法效率。

快排之所以被称为“快”排,是因为它在平均时间上说最快的,主要原因是硬件方面的,每趟快排需要指定一个“支点”(也就是作为分界点的值),一趟中涉及的所有比较都是与这个“支点”来进行比较的,那么我们可以把这个“支点”放在寄存器里,如此这般,效率自然大大提高。除此之外,快排的高效率与分治思想也是分不开的。

二.算法思想

按照快排的思想,对一已知序列排序有如下步骤:

1.指定“支点”

注意,是“指定”,并没有明确的约束条件,也就是说这个支点是任意一个元素,一般我们选择两种支点:当前序列首元,或者随机选取

两种方式各有优劣,前者胜在简单,但可能影响算法效率

快排中,支点的最终位置越靠近中间位置效率越高,读起来可能有点怪怪的,注意支点是一个值(具体元素),而不是字面意思的位置,当支点在最终序列中的位置靠前或者靠后时算法效率都不高(类似于“最坏情况”)

因此,后者在一定程度上减少了最坏情况的发生次数,但随机选取需要耗费额外的时间

所以在具体应用中一般采用第一种方式来指定“支点”,也就是直接把当前序列的首元作为“支点”

2.进行一趟快排

快排中,一趟操作的最终目的是把“支点”放到它应该去的地方,举个例子,已知序列{7, -1, 5, 23, 100, 101},那么第一趟快排的结果是{_, _, 7, _, _, _}

可以看到,首元(支点)已经去了它该去的地方(在最终的结果序列中,7就在中间位置,没错吧)

3.对子序列进行快排

第2步不仅确定了7的最终位置,还把原序列自然地划分为两个子序列{_, _}和{_, _, _},这里用"_"代替具体的数值,因为我们也不知道第2步的结果具体是什么,除非真正地做一趟快排,当然,在这里不必要,下面会有针对具体例子的详细解释

很自然的我们想到了对子序列进行同样的操作,然后对子序列的子序列再进行同样的操作...递归

当所有的子序列长度都为1的时候,排序结束

三.具体实例

现有一序列{9, 0, 8, 10, -5, 2, 13, 7},我们用快速排序算法来对其排序

首先,声明一些特殊的记号,便于描述

a, 数字后面跟的大写字母表示指针,例如2.5P表示指针P指向元素2.5所在的位置

b, @表示垃圾数字,也就是说,当前位置是几都无所谓,不必纠结于此,后面会有具体解释

c, _表示该位的元素与上一行一样(_表示不变)

-------

P.S.想要真正弄明白的话,现在拿出纸和笔吧,光靠眼睛是绝对不够的

下面正式开始一趟快排的过程解析

【1】9L  0  8  10  -5  2  13  7H

【2】7  0L  _  __  __  _  __  @H

【3】_  _  8L  __  __  _  __  __

【4】_  _  _  10L  __  _  __  __

【5】_  _  _  @L  __  _  13H  10

【6】_  _  _  __  __  2H  13  __

【7】_  _  _  2  -5L  @H  __  __

【8】_  _  _  _  -5  @HL  __  __

【9】_  _  _  _  __  9HL  __  __

解释:

1.第一行是初始状态,快排需要两个指针L和H(表示低位Low,高位High),一个临时变量temp

初始时,低位指针L指向首元9,高位指针H指向尾元7,temp=首元9(temp就是所谓的”支点“)

2.进行如下操作:(先不要问为什么)

比较*H与temp,若*H大,则向前移动H继续比较,若*H小,则*L = *H,*H = @(H指向的值变成垃圾数字了),向后移动L

因为7 < 9,所以把L指向的9变成7,把H指向的7变成垃圾数字,向后移动L指针,得到第二行的结果

3.进行如下操作:(先不要问为什么)

比较*L与temp,若*L小,则向后移动L继续比较,若*L大,则*H = *L,*L = @(L指向的值变成垃圾数字了),向前移动H

因为0 < 9,所以向后移动L,得到第三行的结果

4.因为8 < 9,同上

5.因为10 > 9,所以把H指向的垃圾数字@变成10,把L指向的10变成垃圾数字,向前移动H指针,得到第5行的结果

6.因为13 > 9,所以向前移动H指针,得到第6行的结果

7.因为2 < 9,所以把L指向的垃圾数字@变成2,把H指向的2变成垃圾数字,并向后移动L指针,得到第7行的结果

8.因为-5 < 9,所以向后移动L指针得到第8行的结果

9.进行如下操作:(先不要问为什么)

若L = H,则*L = *H = temp,一趟快排结束

因为L指针与H指针重合了,所以把L指向的垃圾数字@变成temp的值9,一趟结束

至此,我们确定了支点9的最终位置,给定序列也被自然的分为两个子序列{7, 0, 8, 2, -5}和{13, 10},对子序列进行相同的操作,最终能够得到有序序列

-------

下面来解释上面提到的三组操作

简单的说,上面的三组操作上为了找出temp的最终位置,每一步都保证L前面都比temp小,H后面都比temp大。所以,H与L重合的位置上的元素只能是temp的值了

上面提到的三组操作可以简化成下面的几条规则,便于记忆:

1.L指向的值小则L移动,反之赋值并移动指针

2.H指向的值大则H移动,反之同上

3.若HL重合,则赋值temp

4.H,L轮流与temp比较,规则是赋值一次后算一轮结束(所以一开始也可以从L与temp开始比较,下一轮H与temp比,再下一轮...)

P.S.至于怎么移动,自然是低位指针只能向高位移动,反之亦然。至于赋值后移动哪个指针,当然是另一个指针(非当前指针)了

四.总结

排序算法的应用都需要结合具体环境来考虑,例如若给定序列部分有序,自然是折半插入算法最快...

快速排序也并不是最好的,它的”快“是建立在综合考虑的基础上,具体情况则不一定

快速排序也不是万能的,例如当给定序列规模很小时,选择排序就要比快排好很多

另外,常见的排序算法有:

1.桶排序/箱排序(Bucketsort)

2.基数排序(Radixsort)

3.插入排序(Insertsort)

4.选择排序(Selectsort)

5.归并排序(Mergesort)

6.快速排序(Quicksort)

7.堆排序(Heapsort)

排序算法之快速排序(Quicksort)解析的更多相关文章

  1. 排序算法TWO:快速排序QuickSort

    import java.util.Random ; /** *快速排序思路:用到了分治法 * 一个数组A[0,n-1] 分解为三个部分,A[0,p - 1] , A[p] , A[p + 1, n-1 ...

  2. 排序算法之快速排序QuickSort

    挖坑填数-快速排序 1. left = L,right = R;将基准数挖出形成第一个坑s[left]; 2. right --; 由后向前找比它小的数,找到后挖出此数填前一个坑s[left]中. 3 ...

  3. Java常见排序算法之快速排序

    在学习算法的过程中,我们难免会接触很多和排序相关的算法.总而言之,对于任何编程人员来说,基本的排序算法是必须要掌握的. 从今天开始,我们将要进行基本的排序算法的讲解.Are you ready?Let ...

  4. Python之排序算法:快速排序与冒泡排序

    Python之排序算法:快速排序与冒泡排序 转载请注明源地址:http://www.cnblogs.com/funnyzpc/p/7828610.html 入坑(简称IT)这一行也有些年头了,但自老师 ...

  5. Java排序算法之快速排序

    Java排序算法之快速排序 快速排序(Quicksort)是对冒泡排序的一种改进. 快速排序由C. A. R. Hoare在1962年提出.它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分 ...

  6. 排序算法之快速排序Java实现

    排序算法之快速排序 舞蹈演示排序: 冒泡排序: http://t.cn/hrf58M 希尔排序:http://t.cn/hrosvb  选择排序:http://t.cn/hros6e  插入排序:ht ...

  7. 常用排序算法之——快速排序(C语言+VC6.0平台)

    经典排序算法中快速排序具有较好的效率,但其实现思路相对较难理解. #include<stdio.h> int partition(int num[],int low,int high) / ...

  8. javascript高级排序算法之快速排序(快排)

    javascript高级排序算法之快速排序(快排)我们之前讨论了javascript基本排序算法 冒泡排序 选择排序 插入排序 简单复习: 冒泡排序: 比较相邻的两个元素,如果前一个比后一个大,则交换 ...

  9. javascript数据结构与算法--高级排序算法(快速排序法,希尔排序法)

    javascript数据结构与算法--高级排序算法(快速排序法,希尔排序法) 一.快速排序算法 /* * 这个函数首先检查数组的长度是否为0.如果是,那么这个数组就不需要任何排序,函数直接返回. * ...

  10. Python实现排序算法之快速排序

    Python实现排序算法:快速排序.冒泡排序.插入排序.选择排序.堆排序.归并排序和希尔排序 Python实现快速排序 原理 首先选取任意一个数据(通常选取数组的第一个数)作为关键数据,然后将所有比它 ...

随机推荐

  1. (动态规划)有 n 个学生站成一排,每个学生有一个能力值,从这 n 个学生中按照顺序选取kk 名学生,要求相邻两个学生的位置编号的差不超过 d,使得这 kk 个学生的能力值的乘积最大,返回最大的乘积

    第2关:最强战队 挑战任务 绿盟和各大名企合作,举办编程能力大赛,需要选拔一支参赛队伍.队伍成员全部来自“绿盟杯”中表现优秀的同学,每个同学都根据在比赛中的表现被赋予了一个能力值.现在被召集的N个同学 ...

  2. Neuron network

    关于神经网络你不能不知道的一切 作者|Kailash Ahirwar 编译|Sambodhi 编辑|Vincent AI前线导语:理解什么是人工智能,以及机器学习和深度学习是如何影响人工智能的,这是一 ...

  3. FileUpload控件实现单按钮图片自动上传并带预览显示

    FileUpload控件实现单按钮图片自动上传并带预览显示 1.实现原理:   FileUpload控件默认不支持服务端的ONCHANGE事件,此时用一种变通的方法借用客户端的onchange事件,调 ...

  4. TZOJ 4839 麦森数(模拟快速幂)

    描述 形如2^P-1的素数称为麦森数,这时P一定也是个素数.但反过来不一定,即如果P是个素数,2^P-1不一定也是素数.到1998年底,人们已找到了37个麦森数.最大的一个是P=3021377,它有9 ...

  5. c语言定义函数指针和typedef简写

    二种方法来定义函数指针 #include<stdio.h> #include<stdlib.h> #include<Windows.h> int add(int a ...

  6. sublime 配置python环境

    1. 在工具栏点击Preferences,打开Browse Packages.在打开的文件夹中找到Python,并打开这个文件夹.找到文件Python.sublime-build,并打开. 2. 修改 ...

  7. JAVA规则引擎JSR-94笔札

    JAVA规则引擎JSR-94笔札 JSR-94 是由JCP(Java Community Process)组织所制定的java规则引擎API的java请求规范.它主要定义了规则引擎在java运行时的一 ...

  8. Laravel 5.4+Vue.js 初体验:Laravel下配置运行Vue.js

    生产材料PHP:PHP 5.6+Laravel 5.4:https://github.com/laravel/laravel/releases/Composer:http://getcomposer. ...

  9. bitnami redmine svn配置

    采用bitnami 方案安装redmine svn服务器端会自己进行安装 1.创建版本库 首先进入remine安装目录的subversion/bin目录,例如我的安装目录是“/opt/redmine/ ...

  10. C语言点滴

    static修饰的变量和函数不可以在其他文件extern引用该变量或者函数. static变量放在静态内存区. static变量赋值只生效一次,再无法调用赋值语句.但是可以运算,例如++等. exte ...