数据结构与算法-排序

分类

        排序算法          时间复杂度             是否基于比较           是否稳定排序         是否原地排序

        冒泡                 O(n^2)                          是                               是                                是

        插入                 O(n^2)                          是                               是                                是

        选择                 O(n^2)                          是                               否                                是

        快排                 O(n*logn)                      是                               否                                是

        归并                 O(n*logn)                      是                               是                                否

        桶                     O(n)                              否                               是                                否

        计数                 O(n+k) k是数据范围     否                                是                                否

        基数                 O(k*n) k是维度             否                                是                                否

如何分析排序算法

    算法执行效率

        1.分析最好情况、最坏情况、平均情况时间复杂度 && 排序算法在不同数据下的性能表现

        2.时间复杂度考虑系数、常数、低阶

        3.考虑比较次数和交换(或移动)次数

            基于比较的排序算法执行过程,会涉及两种操作: 元素比较大小 和 元素交换或移动

    衡量空间复杂度                

    算法稳定性: 稳定的排序算法(针对数据多次排序后的前后顺序始终不变)和不稳定多排序算法

冒泡排序(Bubble Sort)

    特点

        冒泡排序只会有操作相邻的两个数据,两种操作: 比较 和 交换

        排序过程

            每次冒泡操作都会对相邻的两个元素进行比较,看是否满足大小关系要求。

            如果不满足就让它俩互换。

            一次冒泡会让至少一个元素移动到它应该在的位置,重复n次就完成n个数据的排序工作

        属于原地排序算法

            冒泡过程只涉及相邻数据的交换操作,只需要常量级的临时空间,空间复杂度为O(1)

        稳定的排序算法

            当相邻两个元素大小相等时,我们不做交换,相同大小的数据在排序前后不会改变顺序

        时间复杂度

            最好情况时间复杂度为O(n): 数据已顺序排列

            最坏情况时间复杂度为O(n^2): 数据已倒序排列

            平均情况时间复杂度为O(n^2)  

                简单分析方式:有序度 和 逆序度 两个概念来进行分析

                有序度: 数组中具有有序关系的元素对的个数(有序元素对:a[i] <= a[j],如果i < j)

                逆序度:  数组中具有逆序关系的元素对的个数(逆序元素对:a[i] > a[j],如果i < j)

                满有序度:  完全有序的有序度,计算公式: n*(n-1)/2

                公式: 逆序度 = 满有序度 - 有序度

                排序的过程是一种增加有序度,减少逆序度的过程,最后达到满有序度,即排序完成

    示例: 我们要对一组数据4、5、6、3、2、1,从小到到大进行排序,冒泡排序过程如下: 

插入排序(Insertion Sort)

    特点

        插入排序会操作当前数据与已排序区间数据,两种操作: 比较 和 移动

        数组中的数据分为两个区间: 已排序区间和未排序区间。

        初始已排序区间只有一个元素,就是数组的第一个元素。

        排序过程

            取未排序区间中的元素,在已排序区间中找到合适的插入位置将其插入,并保证已排序区间数据一直有序。

            重复这个过程,直到未排序区间中元素为空,算法结束。

        属于原地排序算法        

            插入排序算法的运行并不需要额外的存储空间,空间复杂度为O(1)

        稳定的排序算法

            对于值相同的元素,可以将后面出现的元素,固定插入到前面出现元素的后面

        时间复杂度

            最好情况时间复杂度为O(n): 数据已顺序排列

            最坏情况时间复杂度为O(n^2): 数据已倒序排列

            平均情况时间复杂度为O(n^2)  

                每次插入操作都相当于在数组中插入一个数据,循环执行n次插入操作

        示例: 我们要对一组数据4、5、6、3、2、1,从小到到大进行排序,插入排序过程如下: 

选择排序(Selection Sort)

    特点

        数组中的数据分为两个区间: 已排序区间和未排序区间。

        排序过程

            选择排序每次会从未排序区间中找到最小的元素,将其放到已排序区间的末尾

        属于原地排序算法

            插入排序算法的运行并不需要额外的存储空间,空间复杂度为O(1)

        不稳定的排序算法

            每次都要找剩余未排序元素中的最小值,并和前面的元素交换位置,破坏了稳定性

        时间复杂度

            最好情况时间复杂度为O(n^2): 数据已顺序排列

            最坏情况时间复杂度为O(n^2): 数据已倒序排列

            平均情况时间复杂度为O(n^2)  

示例: 我们要对一组数据4、5、6、3、2、1,从小到到大进行排序,选择排序过程如下: 

总结

                                            是否原地排序        是否稳定        最好、最坏、平均时间复杂度

                冒泡排序                是                        是                    O(n)        O(n^2)        O(n^2)

                插入排序                是                        是                    O(n)        O(n^2)        O(n^2)

                选择排序                是                        否                    O(n^2)     O(n^2)        O(n^2)

        排序算法优先级: 插入排序 > 冒泡排序 > 选择排序

        插入排序对比冒泡排序,时间复杂度一样但赋值代码次数少,执行时间效率高于冒泡排序

归并排序(Merge Sort)

        特点

            分治思想,将一个大问题分解成小的子问题来解决

            分治算法一般是用递归来实现。分治是一种解决问题的处理思想,递归是一种编程技巧

            排序过程

                递推公式                

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

                终止条件

                    p >= r  不用再继续分解

                merge_sort(p...r)表示,给下标从p到r之间的数组排序

                merge_sort(p...r)拆分为: merge_sort(p...q)和merge_sort(q+1...r),下标q = (p+r)/2

                将下标 从p到q 和 从q+1到r 这两个子数组分别排序,递归拆分

                最后将两个有序的子数组合并,即排序完成

            不是原地排序算法

                归并排序中合并函数,合并两个有序数组为一个数组时,需借助额外存储空间

                空间复杂度为O(n):    

                    任意时刻,CPU只会有一个函数在执行,只会使用一个临时内存空间

                    临时内存空间最大也不会超过n个数据的大小

            稳定的排序算法

                关键点合并函数: 两个有序子数组合并成一个有序数组的代码

                保证固定顺序合并,可以保证合并前后的先后顺序不变

            时间复杂度

                最好/最坏/平均情况时间复杂度为O(nlogn)

                    T(1) = C;                         n=1时,只需要常量级的执行时间,所以表示为C

                    T(n) = 2 * T(n/2)  +  n;    n>1

                    T(n) = Cn + n*logn

                    T(n) = O(n*logn)                   

示例: 我们对一组数据11、8、3、9、7、1、2、3,从小到到大进行排序,归并排序过程如下: 

快速排序(Quick Sort)

    特点

        分治思想

        排序过程

            选择分区点(pivot): 从数列中挑出一个元素

            分区(partition): 重排数列,小于pivot放左边,大于pivot放右边,将pivot放中间

            递归(recursive)把小于pivot元素的子数列和大于pivot元素的子数列各自排序

            递推公式:            

                quick_sort(p...r) = quick_sort(p...q-1) + quick_sort(q+1, r)

            终止条件:

                p >= r

        原地排序算法

            关键点在于分区函数,分区函数原地完成分区操作,来实现空间复杂度为O(1)即可

            见 原地分区操作实现图

        不稳定的排序算法

            分区操作时出现数据交换,相同的数值无法实现稳定点排序

        时间复杂度

            最好情况时间复杂度为O(nlogn): 分区极其均衡

                每次分区都能拆分为两个大小接近相等的小区间

                T(1) = C;当n=1时,只需要常量级的执行时间,所以表示为C

                T(n) = 2 * T(n / 2) + n;n>1

            最坏情况时间复杂度为O(n^2): 分区极其不均衡

                例如有序数组每次取最后一个做为分区点

            平均情况时间复杂度为O(n*logn)  

                T(n)在大部分情况下时间复杂度为O(n*logn),只有在极端情况下,才会退化到O(n^2)

快速排序算法实现图
原地分区操作实现图

归并排序 PK 快速排序            

    快排和归并 -> 分治思想

归并排序: 由下到上先处理再合并,稳定排序、时间复杂度O(nlogn)、非原地排序

快速排序: 由上到下先分区再处理,不稳定排序、时间复杂度O(nlogn)、原地排序(内存占用少)

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