算法学习笔记(1) 快速排序

1.快速排序的由来

快速排序是一种二分的排序算法,这种算法的诞生来自于对有序数组的观察。我们假设有以下数组:

1,2,3,4,5,6,7,8,9

这是一个已经按照从小到大排序完毕的有序数组。观察以上数组,取其中间数5,我们可以发现5以左的数1,2,3,4均比5小,5以右的数6,7,8,9均比5大。我们以5为分界线将数组分为两部分:

1,2,3,4
6,7,8,9

分别取中间数3和8,我们可以得到同样的结论:左边的数总小于中间数,右边的数总大于中间数。由此可见,一个有序数列的每一个二分子数列总满足中间数以左的数小于中间数,中间数以右的数大于中间数

快速排序的基本思想就是:

  1. 使完整数组满足A段所有数小于B段所有数,但A段与B段内部不一定有序。
A B
3,2,1,4 7,9,6,8
  1. 使A段内A_1段所有数小于A_2段所有数,B段内B_1段所有数小于B_2段所有数,但每一小段内不一定有序。
A_1 A_2 B_1 B_2
1,2 3,4 7,6 9,8
  1. 以此类推二分数组,直到每个数组内都只有一个元素时,整个数组便变得有序了。

可见快速排序是一个典型的二分算法,且可以使用递归的方式实现。

2.快速排序的基本方法

我们以刚才举例的数组的逆序列为例:

9,8,7,6,5,4,3,2,1

假如我们采用单向迭代的方法来完成快速排序,取中间数为9,之后扫描后面8个数字。由于8个数字均小于9,我们只需要将9插到队伍的最后。

8,7,6,5,4,3,2,1,9

再取中间数为8,扫描后面8个数字,发现只需要把8插到9的前面就行。以此类推,在数据规模为n的情况下,需要n-1次插入。

但是,这是在我们事先已经知道有成块的子串中所有的数均小于中间数的情况下得出的结论。实际情况下,在我们考虑单独的数时,这个数小于中间数并不意味着下一个数小于中间数。所以我们每次选取中间数后需要维护两个序列,一个储存比中间数小的数,一个储存比中间数大的数。每次扫描数,都要与中间数比较后,加入两个序列中的一个当中。每一次选取中间数,复制数都需要n-1次操作,总共选取n个中间数的话,这趟快速排序的时间复杂度就是o(n^2)。因此,我们必须保证所有数据位置的变换都在原数组内部进行。

我们又知道,假如有一排积木紧密排在一起,要将其中的一块移到另一块积木处,就必须得把原来在该位置的积木拿开。

令积木大小不同,如果我们要实现积木从左到右由小到大的排序,可以想象我们一开始将最左边积木拿开,再从右往左找,如果见到了比拿开的积木更小的积木,就拿到最左边的空位。这时右边就空出来了一个积木的空位,我们再从左往右找,找到一块比拿开的积木大的积木,放到右边的空位……

直到空位出现在队伍中间时,左边的积木,尽管还不是从小到大排列的,但至少都拿开的积木,也小于右边的积木。我们再把拿开的积木放回空位,就完成了第一次排序。接着再对右边的积木和左边的积木重复同样的操作,最终整个数组就会变成有序的。

拿开的积木就是我们的基准数,积木的大小就是数组中数字的大小,上面积木排序的过程其实就是数组快速排序的过程。这样的操作时间复杂度是多少呢?由于我们二分地选择基准数,基准数的选择是logn次,考虑最坏的情况,每一段数列中除了基准数外的数中,有一半的数需要移动,对于完整数列即\frac {n-1}{2}次,随着数列二分,数据规模以\frac {1}{2}为公比缩小,根据等比数列求和公式,得:单边移动次数=\frac {\frac{n-1}{2}·(1-\frac{1}{2}^{logn})}{1-\frac{1}{2}}
\lim n→+∞时,单边总共移动次数为n-1,加上我们需要选择logn次基准数,总的时间复杂度就是o(nlogn)

3.快速排序的实现

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

推荐阅读更多精彩内容