使用快速排序在O(n)内查找指定的第K大元素

好了,我们继续来讲排序。
我们前两篇文章讲了三种排序,名字都不一样,但是时间复杂度都一样的——O(n^2)。这种比较高的时间复杂度,比较适合小规模的数据。

那么今天我们不能再讲小规模了,我们要讲讲适合大规模数据排序的算法,其时间复杂度为O(nlogn)。他们都是谁呢?——快速排序和归并排序

那么这两个排序的特点在哪里呢?——分而治之的思想
这个分而治之的思想很重要,我们可以用它解决非排序的问题
比如这篇blog的题目——如何在O(n)的时间复杂度内查找一个无序数组中的第K大元素?


好,我们一个一个来,先看看归并排序——

归并排序的思想——如果要排序一个数组,我们先把数组分为前后两个部分,(从中间来分),然后呢,对这个分好的前后两个部分分别排序。两个子数组排序成功后,再合并在一起就好。

In this way, 两个子数组合并成的整个数组就有序了。我们来看张示意图——


归并排序原理图

从上图中,我们可以看到,一共8个数字,分为了4 4个数字分别为一组。其中11 8 3 9再次分裂,成为11 8和3 9,然后再次分裂,成为11、 8、3、9四个集合。这时候每个集合中只有一个元素了,所以不能再分了。那分解完了,接下来就是合并。
合并时候要从小到大拍,1变2,2变4,然后4变8.
我认为写代码的一个难点就是在合并的时候进行从小到大的排序。

我们来畅想一个问题,如果原数组中的元素是奇数,假设是9个的话。第一次分,分为4和5。4个元素的不必多说,剩下呢个5个的,依然是奇数,继续分成2和3,然后3变成2和1,2最后再变成1和1.


其实看了上面的不断将大问题变成小问题的思想,跟之前我们学习的递归是非常相像的。
可以说,分而治之递归二者的区别在于——分治是一种解决问题的处理思想,递归则是一种编程技巧。

好,那么我们下来的重点就是如何用递归来实现归并排序

递推公式:

merge_sort(p...r) = merge(merge_sort(p...q), merge_sort(q+1...r))

终止条件:

p >= r 不用再继续分解

我们来解释一下这个递推公式,merge_sort(p...r)表示给下标从p到r之间的数组进行排序。
等式右边则是转化为两个子问题, 其中q是p和r的中间值,也就是(p+r)/2。将两个子问题搞定后,再合并,整个就搞定了。

我们上面就说过一个问题,就是我认为的一个难点,它是什么来着——如何将分裂开来的子元素在合并的时候可以保证在合并完成后其合并后的数组也是有序的?

解决方法是什么呢?——

  • 第一,我们先申请一个临时数组tmp,大小与A[p...r]相同。
  • 第二,我们再用两个游标i和j,分别指向A[p...q]和A[q+1...r]的第一个元素。
  • 第三,比较这两个元素A[i]和A[j],如果A[i]<=A[j],我们就把A[i]放入临时数组tmp中,同时i需要后移一位,否则,将A[j]中的元素放入数组tmp中,同时j后移一位
  • 第四,不断重复这个过程,直到其中一个子数组中的所有数据都放入tmp临时数组中,然后,再把另一个数组中的数据依次加入到临时数组的末尾,这个时候,临时数组tmp中存储的就是两个子数组合并之后的有序的数组啦~。
  • 第五,也就是最后,将临时数组tmp中的数据copy到A[p...r]中。
数组分裂后再合并为有序数组的原理图

有个问题,我们在编写merge函数时,如果使用之前提到的哨兵,会是什么样的?


再来解决之前问过的三个问题——

第一,归并排序是稳定的排序算法吗?
  • 是的
第二,归并排序的时间复杂度是多少?
  • 首先,merge()函数合并两个有序子数组的时间复杂度是O(n),然后详细的先不说了。结果是O(nlogn),重点是最好情况、最坏情况、平均情况都是O(nlogn)。
第三,MS的空度是多少?
  • 我们首先要明确的一点是——快排的应用是比归并排序广泛的
    为什么呢?——因为MS不是原地排序算法
    到底是为啥,导致MS不是原地排序算法呢,这是因为MS的merge()函数,在合并两个有序子数组为一个有序数组时,需要借助额外的存储空间。
    它的空度为O(n),为什么空度不能像时度呢样累加呢?因为在任意时刻,CPU只会有一个函数在执行,也就只会有一个临时的内存空间在use。
  • 所以说,由于临时内存空间最大也不会超过n个数据的大小,所以空度为O(n)。

好,我们下来再讲讲快排

快排的原理

我后面将快排写成QS。QS利用的也是分治思想。我们先来看看其核心思想——

如果要排序数组中下标从p到r的一组数据,我们选择p到r之间的任意一个数据作为pivot(分区点)

  • 我们遍历p到r之间的数据,将小于pivot的放在左边,大于pivot的放在右边,of course, pivot放在中间。也就是说,数组p~r之间的数据被分成了3个部分。我们看下图——


    快排核心思想原理图,将一组raw数据,分为3个区间

我们对于这三个区间,第一个和第三个,使用递归排序下标从p到q-1和q+1到r这两个数组中的数据,直到区间的长度缩小为1,此时,说明所有的数据有序。


上面讲的MS中,有一个merge()合并函数。
现在讲的QS中,有一个partition()分区函数

partition()函数的核心就是——随机选择一个元素作为pivot(一般情况下,可以选择p到r区间的最后一个元素),然后对A[p...r]分区,最后,函数返回pivot的下标


上面的MS中,代码的实现有一个临时数组tmp, 在QS中,我们则不一样,我们申请两个临时数组X和Y,遍历A[p...r],讲小于Pivot的copy到数组X,大于的给Y。最后,将数组X和Y中数据顺序拷贝到A[p...r]中。

QS的临时数组

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,843评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,538评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,187评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,264评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,289评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,231评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,116评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,945评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,367评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,581评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,754评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,458评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,068评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,692评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,842评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,797评论 2 369
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,654评论 2 354

推荐阅读更多精彩内容