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

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. BeanDefinitionStoreException: IOException parsing XML document from ServletContext resource

    Tomcat报错如下: BeanDefinitionStoreException: IOException parsing XML document from ServletContext resou ...

  2. 使用DW工具给图片添加热点MAP

    一.准备一张图片.     准备一张需要给不同区域添加不同热点的图片. 二.插入图片: 打开Dreamweaver,新建一个网页,将图片插入到页面中. 三.找到地图工具: 单击鼠标左键点击图片,这时候 ...

  3. swift 移除所有子控件

    /// 移除所有子控件 func removeAllSubViews(){ if self.view.subviews.count>0{ self.view.subviews.forEach({ ...

  4. Kuberentes-入门

    一.kubernetes架构介绍和集群规划 点击链接查看: 系统环境初始化:https://www.cnblogs.com/hwlong/p/9105742.html 二.CA证书创建和分发 点击链接 ...

  5. MVC仓储类Repository

    接口: using Common; using System; using System.Collections; using System.Collections.Generic; using Sy ...

  6. 分享chrome清空缓存开发小技巧

    在打开开发者工具的前提下,左键长按刷新页面小图标(左上角,地址栏左侧),可以调出清空缓存下拉选择项.

  7. centos一键安装lnmp成功后无法访问ip(解决办法)

    自己搞了个服务器 (我的服务器网络类型是 专有网络)如下图点击 配置规则 进入到 进.出端口规则配置 点击添加安全组规则 如图所配置  添加完成后 就如下面所示 (配置完成后 通过ip就已经可以访问了 ...

  8. 什么是tcp协议?

    这是世界上最顶尖的tcp讲解技术...

  9. jquery ui中的dialog,官网上经典的例子

    jquery ui中的dialog,官网上经典的例子   jquery ui中dialog和easy ui中的dialog很像,但是最近用到的时候全然没有印象,一段时间不用就忘记了,这篇随笔介绍一下这 ...

  10. 详解Windows Service Wrapper(winsw.exe)及应用场景

    winsw.exe可以帮助nginx作为windows服务自启动,不需要每次都输入命令,很方便,使用到目前为止这种做法的效果很完美.你得到了 Windows 服务的支持,而且在服务重启时没有遗留孤立的 ...