最近一直在看《编程珠玑》第二版这一本书,里面的东西真的很实用,以前也看过不少讲解快排的书,但是在编程珠玑上看到的讲解是我见过最好理解,也是最详细的,从效率和空间以及实现等各个方面都做了详细说明,并比较了几种变形的快排的效率,所以在这把我看到的内容写出来记录,留着以后忘了的时候看。

1.1.插入排序

首先说一下插入排序,这个会在最后的变形快排中用到,插入排序类似于整理扑克牌的方式,假设之前的序列已经有序,当拿到一个新的数字的时候,只要将其插入到之前的合适位置即可,直到所有数据都被处理完,整个数列就有序了,由插入排序的思想可以分析当原序列基本有序时,插入排序交换的次数是非常少的,所以对于基本有序的序列来说采用插入排序是非常高效的,数据类型对程序程序结构的选择是起到很大的决定性的。插入排序的代码如下:

1 insort()
2 {
3     for(i = 1; i < n; i++)
4         for(j = i; j > 0 && x[j - 1] > x[j]; j--)
5             swap(x,j-1,j);
6 }

1.2.最简单的快排程序

还是说一下快排的基本原理吧,快排的思想基于分治法,首先将数组分成两个小部分,使数组的前一部分值都小于某一个哨兵值t,后半部分都大于t,然后再递归的进行快排这两个子数组,直到数组的元素只剩下一个。在最简单的快排中这样的哨兵值设置为字数组中的第一个值x[l].

最简单的快排划分数组部分的伪代码如下:

1 m = l
2 for i = [l,u]
3     if x[i] < t
4         swap(x,++m,i);

下面利用图示来进行讲解,这样更直观。

如上图所示,假设这是进行了几次简单快排后的数组的状态,当扫描位置到位置 i 时,如果x[i] < 哨兵值x[l]则需要交换m的下一个位置和位置i的值,m的下一个位置指向的是第一个比哨兵值x[l]大的位置.

当循环终止的时候情况如下:

如上图所示此时整个数组的所有元素都已经划分好了,此时m指向的是最后一个比t小的元素的位置,所以只需要交换一下哨兵位置和m位置的值就得到了数组的有序序列,如下图所示。

下面附上简单快排程序的完整的代码:

 1 void qsort1(int l,int u)
 2 {
 3     if(l >= u)
 4     {
 5         return;
 6     }
 7
 8     int i,m = l;
 9     for(i = l + 1; i <= u, i++)
10     {
11         if(x[i] < x[l])
12         {
13             swap(x,++m,i);
14         }
15     }
16
17     swap(x,l,m);
18
19     qsort1(l,m - 1);
20     qsort1(m + 1,u);
21 }

1.3.双向划分的快排程序

双向划分就是设置两个游标分别从数组的左侧,和右侧开始,左侧每次找到比哨兵值t(现在为x[0])大的位置,右侧每次找到比哨兵值t小的位置,如果两个下标没有交叉就交换他们的值,直到,两个游标产生交叉。这种思想可以避免在数组中所有元素都相同时产生平方时间的算法,而是比较差不多n*logn的次数即可,同时可以减少总的比较次数。

双向划分的图示如下:

双向划分的快排程序的代码如下:

 1 void qsort2(int l,int u)
 2 {
 3    if(l >= u)
 4    {
 5         return ;
 6    }
 7
 8    int t = x[l],i = l,j = u;
 9
10    while (i < j)
11    {
12         while(i < j && x[j] >= t)
13             j--;
14         if(i < j)
15             x[i++] = x[j];
16
17         while(i < j && x[i] < t)
18             i++;
19         if(i < j)
20             x[j--] = x[i];
21    }
22
23    x[i] = t;
24
25    qsort2(l,i - 1);
26    qsort2(i + 1,u);
27 }

1.4.哨兵随机,小数组不处理快排

    当数组已经按升序排好序时,会导致快排是o(n2)时间复杂度的,所以使用哨兵值随机划分,可以避免这种情况,方法是把x[l]和x[l..u]中的一个随机项来进行交换,然后在设置x[l]为划分数组哨兵值,实现函数为swap(x[l],x[rand(l,u)])。

  而且当快排进行划分到每个子数组很小时,原来的快排程序花费了大量的时间来排序这小很小的子数组,如果这时用1.1中所介绍的插入排序来排序数组会非常有效,因为当用快排排序到后面的小数组阶段时,数组已经基本有序了,而插入排序对基本有序的数组排序是非常快的,在《编程珠玑》第二版这本书中,作者做了实验,验证出这个小数组的值边界设置为50时,然后再调用插入排序,变形过得快排程序处理最快。

  代码如下:

 1 #define SAMLL_CUTOFF 50
 2
 3 void qsort3(int l,int u)
 4 {
 5
 6    if(u - l < SMALL_CUTOFF)
 7    {//剩下的小数组的时候结束快排,防止对小数组进行大量排序
 8         return;
 9    }
10
11    swap(x,l,rand(l,u));
12    int t = x[l],i = l,j = u;
13
14    while (i < j)
15    {
16         while(i < j && x[j] >= t)
17             j--;
18         if(i < j)
19             x[i++] = x[j];
20
21         while(i < j && x[i] < t)
22             i++;
23         if(i < j)
24             x[j--] = x[i];
25    }
26
27    x[i] = t;
28
29    qsort3(l,i - 1);
30    qsort3(i + 1,u);
31 }

对该快排函数调用时方式如下:

1 qsort3(0,n-1);
2 insort();

1.5.作者进行了效率对比如下表:

程序

时间(纳秒)

C库函数qsort

137n logn

qsort1

60 n logn

qsort2

44n logn

qsort3

36n logn

C++库函数sort

30n logn

l

 1.6.线性选择问题(选出数组中第k小的元素)

线性选择问题可以基于堆排序或者快排做,以前在计算机算法设计与分析那本书上看过这个问题,就放在这里一起记录吧。

解决思路:

由于每次快排将元素分为左右两部分,左边都比哨兵值小,右边都比哨兵值大,所以可以基于这个特性,在每次快排后对哨兵最后交换的位置m进行判断,如果m比k大说明第k小的元素在左边,只需在左边子数组继续边递归找第k小的元素即可,如果m比k小则说明第k小的值在右边,则需要在右边子数组中找第k-m小的元素(由于左侧的m个元素都比k小),直到递归结束后返回x[k-1](因为数组下标从0开始)即可。

基于快排的线性选择代码如下:

 1 void kth_select(int l,int u,int k)
 2 {
 3
 4    if(l >= u)
 5    {
 6      return ;
 7    }
 8
 9    swap(x,l,rand(l,u));
10    int t = x[l],i = l,j = u;
11
12    while (i < j)
13    {
14         while(i < j && x[j] >= t)
15             j--;
16         if(i < j)
17             x[i++] = x[j];
18
19         while(i < j && x[i] < t)
20             i++;
21         if(i < j)
22             x[j--] = x[i];
23    }
24
25    x[i] = t;
26
27    if(j < k)
28    {//第k个元素在右侧,继续在右侧找第k-j个元素
29         kth_select(j + 1,u,k - j);30    }
31    else if(j > k)
32    {
33         kth_select(l,j - 1,k);34    }
35 }

该函数的调用如下,kth_select(0,u - 1,k-1);(数组下标从0开始)

转载于:https://www.cnblogs.com/daimadebanyungong/p/5134017.html

我们聊聊快排吧...相关推荐

  1. seo模拟点击软件_网站排名优化第一课:如何看待快排?SEO排名工具到底香不香!...

    2020年4月13日,一位长沙浏阳市的客户打电话给我,问我怎么能把网站的关键词做到首页,他说现在找的公司用快排系统给他们做排名,但是已经过去三个月了,网站的排名还是没有一点起色,很是捉急.下面我就针对 ...

  2. 链接提交提示安全验证,网站辅助快排不行了吗?

    相信观看冬镜的小伙伴们就会发现,近段时间我很少在做SEO优化,或者写SEO相关的教程文章,确实自从去年中旬开始深度研究百家号后,对网站SEO优化方面的消息关注度有所下降,最近这几天在做第三方平台优化的 ...

  3. 白杨SEO:做百度快排网站会被降权吗?再谈百度SEO快排行业内卷现状及我的看法

    前言:这是白杨SEO公众号原创第328篇.为什么想到再写写百度快排这个?因为我发现从这个词出来到现在几年了,依旧还是有人好奇.在做.怀疑.拒绝,这个魔力是什么,今天就来聊聊,如有启发或帮助,点赞或打赏 ...

  4. 快速排序(快排)--->注释超详细

    基本思想:         1.先选取一个基准值(一般选取数组第一个元素).         2.以第一步选取的基准值为标准,然后从最后一个数值开始一步步向前走将数字与基准值进行比较,如果该值大于基准 ...

  5. java快排算法解读,java 快排的思路与算法

    java 快排的思路与算法 有时候面试的时候的会问道Arrays.sort()是怎么实现的,我以前根本不知道是什么东西,最近点进去看了一下.直接吓傻, //看到这个时候还是比较淡定的,可怕的事情来了. ...

  6. java 快排_八大排序-快速排序(搞定面试之手写快排)

    概要 快速排序由C. A. R. Hoare在1960年提出,是八大排序算法中最常用的经典排序算法之一.其广泛应用的主要原因是高效,核心算法思想是分而治之.快速排序经常会被作为面试题进行考察,通常的考 ...

  7. 排序(一)归并、快排、优先队列等(图文具体解释)

    排序(一) 0基础排序算法 选择排序 思想:首先,找到数组中最小的那个元素.其次,将它和数组的第一个元素交换位置.再次.在剩下的元素中找到最小的元素.将它与数组的第二个元素交换位置. 如此往复,直到将 ...

  8. 快排递归非递归python_Python递归神经网络终极指南

    快排递归非递归python Recurrent neural networks are deep learning models that are typically used to solve ti ...

  9. ACdream 1099——瑶瑶的第K大——————【快排舍半,输入外挂】

    瑶瑶的第K大 Time Limit:2000MS     Memory Limit:128000KB     64bit IO Format:%lld & %llu Submit Status ...

  10. 冒泡链表排序java_链表排序(冒泡、选择、插入、快排、归并、希尔、堆排序)...

    以下排序算法的正确性都可以在LeetCode的链表排序这一题检测.本文用到的链表结构如下(排序算法都是传入链表头指针作为参数,返回排序后的头指针) struct ListNode { int val; ...

最新文章

  1. 前端要完!人工智能已经能实现自动编写 HTML 和 CSS
  2. 【题解】P1508 Likecloud-吃、吃、吃(简单DP)
  3. Javascript事件委托
  4. UOJ #277 BZOJ 4739 定向越野 (计算几何、最短路)
  5. srs代码学习(4)-怎么转发流
  6. python模型_python 模型的释义
  7. android判断某文件下是否you_Android_判断文件是否存在并创建代码
  8. 简明python教程 答案1
  9. android手机微信收藏功能实现,微信小程序收藏功能的实现代码
  10. 身份证某几位用*代替
  11. linux中dd命令增加内存使用率,Linux 下使用 dd 命令进行硬盘 I/O 性能检测
  12. 精美的文言文表白,一起体会吧!
  13. WinSock网络编程基础(1)
  14. C语言绕过杀毒软件,易语言插件规避杀毒软件方法
  15. 2. 匈牙利命名法
  16. 【python小作业】编写函数,接收一个任意字符串,返回其中最长的数字字串。要求使用正则表达式。
  17. linux内存、cpu查看
  18. Albumentations 中的空间级图像变换
  19. python-docx中文文档使用小结
  20. MJ评《贫民窟的百万富翁》-满分10分

热门文章

  1. html th width无效 解决方法
  2. Docker教程小白实操入门(17)--如何使用run -v创建一个数据卷
  3. 去除移动端alert/confirm的网址(url)
  4. 计算机毕业设计最新选题汇总(持续更新)
  5. Floyd 多源最短路径
  6. lol游戏挂机软件_“本不想挂机,但系统不让重连!”LOL成“挂机联盟”,5局3挂机...
  7. map 和 hash_map 的使用方法
  8. 项目2:PHP抽奖程序 ,抽奖规则代码
  9. Activiti 6.0 概述与 Hello World 快速入门 与 核心 API 概述
  10. linux怎么db2命令窗口,Linux 命令行进入DB2