七大排序算法之快速排序

七大排序算法之快速排序

@(算法笔记)[排序算法, 快速排序, C++实现]

[TOC]


快速排序的介绍:

快速排序是C. A. R. Hoare在1962年提出的,平均时间复杂度为O(nlogn)级的高效率算法,也是目前O(nlogn)的排序算法中使用最多的算法,这段时间想把自己学过的算法都整理一遍,于是就写了这篇博客,来记录自己的学习过程吧...也希望能给初学者带来一些帮助。


快速排序的核心思想

每次排序都需要以序列的第一个值为关键值,将序列分成两个部分,并且使其中一部分的值都大于关键值,而另一部分的值都小于关键值,然后再分别对两个部分都再次进行本操作,直至某次操作的部分只有一个值。整个排序过程可以通过递归的方式进行,使整个序列变成有序序列


简单例子

初学者们可能无法看懂上面的描述,不过没关系,让我们来举个栗子:

待排序序列:    5   3   7   6   9   1   2
第一轮排序:    2   3   1   5   9   6   7
第二轮排序:    1   2   3   5   7   6   9
第三轮排序:    1   2   3   5   6   7   9
第四轮排序:    1   2   3   5   6   7   9

第一轮快速排序,把上面这个序列分成了两个部分,然后5作为关键值在中间
第二轮快速排序,分别再对之前的两个序列再进行操作,2和9分别是关键值
第三轮中,只有一个值的序列不再进行操作,现在灰色区域的序列
第四轮中,每个部分都只有一个值了,排序结束

由此可见,快速排序要做的事,就是用二分的思想,每次都将待处理的序列分成两个部分,并且保证其中一个序列的值都大于另一个序列的值,显然,将本操作执行完之后,序列自然就都是有序的了,那剩下的问题只有,每轮的操作该如何实现了。


每轮快排的具体实现

每轮操作该如何执行? 我们要做到以O(n)的时间复杂度,做到让序列分成两个部分,该如何实现呢?

其实这个实现起来并不困难,举个栗子:

初始序列:
5   3   7   6   9   1   2    
我们选中第一个数字5作为关键值,然后先从后往前找比关键值小的数
5   3   7   6   9   1   2
此时我们找到了数字2,它比关键数5要大,于是我们让它和关键数交换
2   3   7   6   9   1   5
关键数到了后面,我们锁定5,转换方向,再从前面开始找比5大的数
2   3   7   6   9   1   5   
此时我们找到了数字7,交换
2   3   5   6   9   1   7    
之后再转换方向,从上一次找到的位置从后往前找比关键值小的数1,交换
2   3   1   6   9   5   7    
与1交换,再从1往后找比5大的数,找到了6,交换
2   3   1   5   9   6   7     
5之后,6之前已经没有比关键字大的数了,结束

这样子一轮操作就结束了,我们也确实在O(n)的时间复杂度内,实现将数组分成两个序列了,看着这个栗子是不是有点天昏地转的感觉?哈哈,没事的,习惯就好了。

用语言来描述每轮的操作就是:锁定一个数为关键数,然后先从尾部往前找比第一个比关键数小的数,找到了交换并交换方向,没找到就结束本轮操作。换方向后,从刚刚交换的位置再往后/前找,找到第一个比关键数大/小的数,交换,直到没找到符合条件的数为止,本轮操作结束。


时间复杂度的讨论

上面的介绍中已经提到了,快速排序算法的时间复杂度是O(nlogn),现在我们来简单地分析一下:

可见,虽然每轮操作中,待处理的序列段会逐渐变多,但需要处理的数字的数量是不会增加的,所以只要让操作的时间复杂度都是O(n) 就行了(此处的n是每段待处理的序列中数值的数量),这样就能保证每轮的时间复杂度都是O(n)。

接着再来讨论算法需要执行几轮:在数列足够乱序的情况下,我们假设每个部分操作完了之后,都会产生左右两个序列,即构造成一个满二叉树,在这个前提下,我们执行n轮,就能解决2的n次方个数的排序。所以只需进行logn次操作就能得到答案。当然,这个前提有点苛刻。但在平均情况(随机序列)下,执行的轮数的数量级都是logn,所以,我们说快速排序的平均时间复杂度是O(nlogn)。

有最好的情况,肯定也有最坏的情况,对快速排序来说,最坏的情况就是待排序的数组本身有序(顺序逆序都是),每次操作的时候,都会出现所有的数都在关键值的同一边的尴尬的情况,使得这个二叉树成了一个单向链表,那么操作的轮数就是n轮了,在这种极端的情况下,快速排序的时间复杂度就是O(n^2)了。


代码

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

推荐阅读更多精彩内容

  • 概述:排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部...
    每天刷两次牙阅读 3,727评论 0 15
  • 概述 排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部...
    蚁前阅读 5,164评论 0 52
  • 概述排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的...
    Luc_阅读 2,255评论 0 35
  • 很偶然的机会在好友的朋友圈看到了21天脑图学习班的消息,心里一阵窃喜。因为,一直以来对思维导图很感兴趣,初识脑图感...
    tyy532703阅读 300评论 0 0