6.排序学习(学习笔记)

2.6.1如何分析一个“排序算法”

①排序算法的执行效率

    从三方面来看:最好情况,最坏情况,平均情况时间复杂度;时间复杂度的系数,常数,低阶;比较次数和交换次数。

②排序方法的内存消耗

    算法的内存消耗可以通过空间复杂度来分析,排序算法也不例外,针对排序算法的时间复杂度,引入了一个新的概念:原地排序即为空间复杂度为O(1)的排序算法。

③算法排序的稳定性

    稳定性:这个概念是说,如果待排序的序列中存在值相等的元素,经过排序之后,先后顺序不发生变化,比如说,2,9,3,4,8,3这组数据,如果排序之后两个三前后顺序没有发生改变,称之为稳定的排序算法,反之则称为不稳定的排序算法。

    假如是一个很复杂的业务,比如有10万条订单数据,要求先按照订单金额进行排序,在订单金额相同的情况下,再根据下单时间进行排序。可以先用稳定的排序方法先对数据进行时间排序,在进行金额排序,排序之后,还是我们想要的数据。

2.6.2冒泡排序

    冒泡排序只会操作相近的两个数据,每次冒泡都会对相邻的两个数据进行比较,看是否满足大小关系要求,如果不满足就让他俩互换,一次冒泡至少会让一个元素移动到他所应该在的位置。重复n次,就完成了n个数据的排序工程。

I’m

    冒泡排序是原地排序算法,是稳定的排序算法,最好情况的时间复杂度是O(n),最坏情况时间复杂度为O(n²)

    平均时间复杂度的分析引入一种新的“不严格”的分析方法,有序度逆序度,有序度指数组中具有有序关系的个数,对于一个倒序排列的数组,比如说6,5,4,3,2,1他的有序度就是0,而1,2,3,4,5,6他的有序度就是 n*(n-1)/2也就是15,叫做满有序度,而最好情况有序度就是n*(n-1)/2,最差情况的有序度是0,平均就是n*(n-1)/4,而复杂度上上限是O(n²),所以平均情况下的时间复杂度就是O(n²)。

2.6.3插入排序

    插入排序含有两种操作,一种是元素的比较,一种是元素的移动,移动次数就等于逆有序度。根据其原理,我们把该无序数列看成两个部分,首先我们把第一位4看成是有序数列,剩下的作为无序数列,因为要把后面的无序数列中的数插入到前面有序数列,所以依次把后面的数抽出,在前面找到合适位置插入。如图,先抽出5,与前面比较,比4大放在4后面,再抽出6,与前面比较,比5大,所以插入到5后面。依次类推,直到最后的一个数也插入到前面的有序数列中。

    插入排序是原地排序算法,是稳定的排序算法,如果数组是有序的,最好情况时间复杂度是O(n),最坏情况是倒序的,所以最坏情况时间复杂度是O(n²),平均时间复杂度是O(n²)。

2.6.4选择排序

选择排序的实现思路有点类似于插入排序,也分排序区间和未排序区间,但是选择排序每次都会从未排序区间中找到最小的元素,将其放到已排序区间的末尾。

    选择排序的空间复杂度是O(1),是一种原地排序算法。最好情况、最坏情况、平均情况时间复杂度都是O(n²),但是选择排序是不稳定的排序算法,比如说一组数:5,8,2,5,9。第一次找到的是最小数据2,然后和5交换位置,这样的话第一个5和第二个5的位置就变化了,就不稳定了。

2.6.5三种排序的总结

    选择排序是一种不稳定的排序算法,相比于冒泡排序和插入排序,这都是他的弱点所在,而冒泡排序和插入排序相比,虽然移动(插入)次数相同,时间复杂度也都相同,但是冒泡要赋值三个,而选择排序只需要一个。

    以上这三种算法,都有一个共同点,将待排序的序列分为已排序和未排序两部分,都是在未排序的部分找到一个最值,放到已排序序列的恰当位置。具体到代码里面,分两层循环,外层循环用于分割已排序和未排序部分,内层循环用于在未排序的部分中查找。

2.6.6归并排序

    归并排序采用一种分治思想(将一个大问题分解成小的问题来解决,小的问题解决了,大问题也就解决了)。先把一个无序数组从中间分成前后两部分,然后对前后两部分分别排序,再将排好序的部分合并起来,这样这个数组就有序了。

    分治和递归思想有点像,分治一般是通过递归来实现的,分治是一种解决问题的处理思想,递归是一种编程技巧。

    性能分析:首先归并排序是稳定性的排序算法,时间复杂度的分析:归并排序的涉及递归,假设解决问题的时间复杂度是T(a),那么分解成两个问题,就是T(a)=T(b)+T(c)+k,其中k等于合并两段数据所消耗的时间。假设n个元素进行归并排序所需要消耗的时间是T(n),那么分解成两部分就是T(n/2)*2加上合并所需要的时间复杂度n。

    最终分析得到T(n)=2^k*T(n/2^K)+k*n,假设n=1,当T(n/2^k)=T(1)时,也就是n/2^k=1,得到k=log2n,带入到公式里面得到T(n)=Cn+nlog2n,用大O标记法来表示,他的时间复杂度就是O(nlogn),从空间复杂度来看,归并排序有一个致命的缺点就是,他不是原地排序的排序算法,他的空间复杂度是O(n)

2.6.7快速排序

    以下快排的实现思路是,从数组中取一个值作为基准(以下取得是第一个值),然后从左向右开始遍历找到那个比他大的值,从右向左开始遍历,找到那个比他小的值。然后将两个数的位置进行置换,然后把基准的位置和小的那个值位置互换。然后以此下标为基准,进行分区分治。


    再谈一种快排的思路,大体实现是相同的,以数组中的一个值为基准(以最后一个数为基准),遍历数据,把小于pivot的放在左边,大于pivot的放在右边,pivot就在中间。,然后对两边进行分区分治。最后实现快排。

    快排分析:快排是一种原地不稳定的排序算法,快排的时间复杂度分析方法和归并排序一样,也是O(nlogn),但是在极端情况下,比如1,2,3,4,5如果选择最后一个元素作为pivot,那么每次分区得到的都是不均等的,需要大约进行n此操作,才能完成快排过程,这种情况下,快排的时间复杂度就从O(nlogn)退化成了O(n²)。

    问题分析1:O(n)时间复杂度内求无序数组中第K大元素(使用第二种解题思想来实现的)

    选择数组A[0...n-1]来进行分析,以最后一个数为基准来判断,对数组进行原地分区,这样就分成了三部分,A[0...p-1]、A[p]、A  [p+1...n-1]。如果要找到第K大的数,那么如果p+1=K。那么p就是那个数,如果K<p+1,那么这个数就在左边的区间找,那么来看为什么上面的时间复杂度是O(n),第一次要找这个数时,我们要遍历整个数组,这时时间复杂度是O(n),第二次我们平均情况下只需要在n/2的区间内进行分区查找,第三次是在n/4......累积起来就是n+n/2+n/4+n/8+...1,利用等比求和求得最后的和是2n-1,也就是时间复杂度是O(n)。

(本文是个人听课笔记,不少东西摘取于王争老师的原文,原文链接http://gk.link/a/10aMZ)

2.6.8线性排序

桶排序,计数排序,基数排序,因为这些排序算法的时间复杂度都是线性的,所以把这类排序算法称为线性排序。这三个算法都是基于比较的排序算法,都不涉及元素之间的比较操作。

2.6.9桶排序

 

    桶排序的核心思想就是将要排序的数据分到几个有序的桶里,然后每个桶里的数据在进行单独的排序,桶内拍完序之后再把每个桶里的数据按照顺序依次的取出,组成的序列就是有序的了。桶排序的时间复杂度是O(n)。如果要排序的数据是n条,平均的分配到m个桶里,然后对每个桶里进行快排,每个桶里有k=n/m个元素,每个桶的时间复杂度就是O(klogk),m个桶的时间复杂度就是O(m*k*logk),当桶的数量无限接近于元素的数量的时候,logk就会变成一个非常小的常量,这时桶排序的时间复杂度就变成了O(n)。

    这样看起来桶排序很好啊,那是不是其他的排序就没有必要了,当然不是。桶排序对于数据的要求太高了,首先要排序的数据要很轻易地能划分进m个桶,并且桶与桶之间要有天然的大小顺序,其次数据要在各个桶之间是分布均匀的,如果数据经过桶的划分之后,有的桶数据非常多,有的桶数据非常少,很不平均,那样的话桶内的时间复杂度就不是常量级了,在极端情况下,如果所有的数据全部都分布到一个桶里,那样的话,时间复杂度就又变成O(nlogn)了。

    说一个比较适合桶排序的场景。桶排序比较适合用在外部排序中,就是数据存储在外部磁盘中,数据量比较大,内存有限,无法将数据全部加载到内存中。比如说有10GB的数据,希望按照订单金额(假设都是正整数)进行排序,但是内存有限,只要几百MB,没办法一次性全部加载到内存中,应该怎么办:

    用桶排序来解决这个问题,先扫描一遍文件,看金额所处的数据范围,假设最低是1,最大10万,将数据划分进100个桶里,第一个桶是1-1000,第二个1001-2000...并且按照金额范围的大小顺序对编号命名(00,01,02...)。最理想的情况下,如果订单金额在1元-10万元内均匀分布,那订单会被分布到100个桶里,每个桶的大小也就是100MB,对桶里的数据进行快排,只需要按照桶的编号从头开始读取数据并存取到一个文件中即可。

    以上是理想的情况,但是怎么可能呢!有可能有的区域数据多,那样的话就会超出100MB,那样的话针对于这些比较大的文件(桶)就继续划分出更小的区间...直到能够一次性读入内存为止。

2.6.10计数排序

    计数排序像是桶排序的一种特殊情况,加入有n个数据,最大值是k,就分配k个桶,将n个数据分配到k个桶里,每个桶里的数据都是相同的。比如说高考分数排序,假设50万人的分数,分到0-900分这901个桶里。桶内都是相同的数据,所以并不需要进行排序,因为只涉及扫描操作,所以时间复杂度是O(n)。

    不过,为什么叫“计数”排序呢,假设8个考生,成绩2,5,3,0,2,3,0,3,存放到数组A中,然后按照分数排序放到有序数组中:然后推断出每个分数在有序数组中的存储位置:



    首先是从其那到后到前依次扫描数组A,比如:当扫描到3时,看数组C的下标为3的值,7表示小于等于3的共有7个数,然后把3作为第七个元素放入B数组的第七个位置,与此同时C数组中3下标的值减一变为6。这是一种利用另一个数组来计数的方式,所以叫计数排序。

    实现代码如下:


    计数排序要在数据范围k和数据量n相差不大的情况下进行排序,如果n比k大太多,就不适合计数排序了,而且计数排序只能给非负整数排序,如果要排序的是其他的数据类型,就要先传换为非负整数。(比如,如说分数排序,分数后面有小数,就得要先乘10在进行排序)

2.6.11基数排序

    假如要排序10万个手机号码,希望将这10万个手机号码进行排序,要采取一种什么排序方法。可以采用基数排序,先按照最后一位排序手机号码,再按照倒数第二位,以此类推,最后到第一位重新排序,经过11次排序之后吗,手机号码就有顺序了。对每一位进行的排序可以运用桶排序或者计数排序,一共有11位,所以时间复杂度就是O(n)。

    荷兰国旗问题:

(本文是个人听课笔记,不少东西摘取于王争老师的原文,原文链接http://gk.link/a/10aMZ)

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

推荐阅读更多精彩内容