排序算法 | 快排、冒泡、堆排、归并、基数、递归、希尔、计数
本文为笔者学习排序算法时整理的学习笔记,包括刷过的练习题目。文中部分题解与图片摘自“牛客网”。因为知识点众多,后续会持续整理更新~
排序期望运行时间复杂度 也就是 平均时间复杂度。
选择适合的排序算法时,需要考虑表中元素的个数。
影响时间复杂度的主要因素为比较的次数。
排序算法中的比较次数与初始元素序列的排列无关 ❌。【只有选择排序和基数排序无关,其余都有关】
对长度为n的线性表排序,在最坏情况下,比较次数是n(n-1)/2的排序方法是快速排序、冒泡排序、直接插入排序。【即:复杂度是O(n²)的排序算法】
平均情况、最好情况和最坏情况下的时间复杂度都为O(n²)的是:直接选择排序。
对n个数字进行排序,其中两两不同的数字的个数为k,n远远大于k,而n的取值区间长度超过了内存的大小,时间复杂度最小可以是O(nlogk)。
现有N条词以及对应的拼音串,对其排序,排序规则:首先按拼音串的字母序排序,如果拼音串相同,则按当前词所在的顺序排序,下列哪些排序算法符合条件?插入排序、冒泡排序。
按当前词所在顺序排序 即 排序算法要稳定。 冒泡排序,插入排序,归并排序,基数排序 都稳定
交换类:快排,冒泡 插入类:希尔,直接插入 选择:堆排序,简单选择 归并类:二路/多路归并
不稳定排序: 同(桶排序)学,快(快速排序)些(希尔排序)选(选择排序)堆(堆排序)。O(n): 统(桶)计(基数排序)个数;O(nlogn): 快(快速排序)些归(归并排序)队(堆排序);O(n^2) 选择(选择排序)冒(冒泡排序)出来的直接插入(直接插入排序);内部排序方法的稳定性是指该排序算法不允许有相同的关键字记录。 ❌
排序方法的稳定性是指在排序过程中是否改变相同元素的相对位置,若不变则稳定,否则不稳定。
稳定:如果 a 原本在 b 前面,而 a = b,排序之后 a 仍然在 b 的前面;不稳定:如果 a 原本在 b 的前面,而 a = b,排序之后 a 可能会出现在 b 的后面;在待排序的记录集中,存在多个具有相同键值的记录,若经过排序,这些记录的相对次序仍然保持不变,称这种排序为稳定排序。精俭排序,即一对数字不进行两次和两次以上的比较,以下是“精俭排序”的是插入排序、归并排序。
辅助空间
直接选择排序:前面逐渐有序,每次从后面的无序数列中找最大或最小继续添加到前面有序数列中,两两交换需要一个辅助空间直接插入排序:类似打斗地主,每次抓一张牌,从后往前比较,把新抓的牌放到合适大小的位置,两两交换需要一个辅助空间冒泡排序:每次把当前无序数列中最大或最小的数交换到此无序数量的最后,两两交换需要一个辅助空间归并排序:分治法把当前待排数组分成多个子序列,先使每个子序列有序,再使子序列段间有序,需要 O(n) 的辅助空间0~999999之间的所有数字中,任何一位都不包括数字3的数字的总数为472392。
首位不能为0和3,其余不能为3:89999*9。尾数是2。
希尔排序和堆排序都利用了顺序存储的随机访问特性,而链式存储不支持这种性质,所以时间复杂度会增加。
对于一个整数数组,想求出数组的最大连续和,不可以用(排序)。
求的是数组的最大连续和,数字的顺序不能变,排序后改变了元素的顺序。
所有内部排序方法都是基于关键字比较的排序方法。 ❌【冒泡排序:相邻元素逐个比较做交换】
排序时,若不采用计数排序的等空间换时间的方法,则合并m个长度为n的已排序数组的最好时间复杂度为(O(mn(logm)))
如果某种排序算法是不稳定的,则该方法没有实际意义。 ❌【一种排序算法适合于某种特定的数据环境,有时对排序的稳定性没有要求】
快速排序:关键节点前面的元素都比它小,后面的元素都比它大; 选择排序:从剩余元素后面找最小元素和当前元素交换; 插入排序:关键元素前面的元素已经排好序。
1. 基数排序稳定排序算法之基数排序
元素的移动次数与关键字的初始排列次序无关的是基数排序。
用基数排序需要进行(最大元素的长度)趟的分配和回收才能使得初始关键字序列变成有序序列。【个位、十位、百位……】
对[21, 49, 84, 45, 12]进行基数排序,第一趟排序的结果为:([21, 12, 84, 45, 49])。
对给定的关键字序列110, 119, 007, 911, 114, 120, 122 进行基数排序, 则第 2 趟分配收集后得到的关键字序列是(007, 110, 911, 114, 119, 120, 122)。
2. 归并排序稳定merge sort排序算法之归并排序
一趟排序结束都至少能够确定一个元素最终位置 ❌【二路归并排序每趟对子表进行两两归并从而得到若干个局部有序的结果,但无法确定最终位置。】
归并排序需要一个跟原始数组同样大小的空间做归并操作。归并排序和基数排序所需辅助空间最多,为O(n)
就排序算法平均所用的辅助空间而言,堆排序、快速排序、归并排序的大小关系是堆排序<快速排序<归并排序。【归并排序需要的附加存储开销最大】
归并排序法的最好时间复杂度和此情况下的空间复杂度分别是O(nlogn) 和O(n)。【归并排序不会退化 无论初始条件什么情况时间复杂度都是0(nlogn)【最坏时间复杂度O(nlogn)】】
外部排序常用的算法是多路归并排序。
归并排序使用了分治策略的思想。
在内部排序时,若选择了归并排序而没有选择插入排序,则可能的理由是归并排序的运行效率更高。
对10TB的数据文件进行排序,应使用的方法是归并排序。
外部排序指待排序文件较大,内存一次性放不下,需存放在外部介质中。外部排序通常采用归并排序法。
希尔排序、堆排序、快速排序都是内部排序的方法。
归并排序算法在输入数据逆序情况下排序速度最快。
假设你只有100MB的内存,需要对1GB的数据进行排序,最合适的算法是多路归并排序。
将N条长度均为M的有序链表进行合并,合并以后的链表也保持有序,时间复杂度为O(N * M * logN)。
将两个各有n个元素的有序表归并成一个有序表,最少的比较次数是(n)
现有1G数据需要排序,计算资源只有1G内存可用,下列排序方法中最可能出现性能问题的是归并排序。
设某文件经内排序后得到100个初始归并段(初始顺串),若使用多路归并排序算法,且要求三趟归并完成排序,问归并路数最少为5。
设一组初始记录关键字序列为(25,50,15,35,80,85,20,40,36,70),其中含有5个长度为2的有序子表,则用归并排序的方法对该记录关键字序列进行一趟归并后的结果为(15,25,35,50,20,40,80,85,36,70)。
若外部存储上有3110400个记录,做6路平衡归并排序,计算机内存工作区能容纳400个记录,则排序好所有记录,需要作5趟归并排序。
每次将工作区装满,共计3110400/400=7776个归并段,对于n路归并排序,m个归并段,需要归并排序的次数为次,代入数据得到答案为5。
对于初始关键字(67,66,77,82,78,51,58),使用二路归并排序,第一趟归并之后其序列变为66,67,77,82,51,78,58。
第一趟执行归并的为(67,66),(77,82),(78,51),(58) 序列变为了(66,67),(77,82),(51,78),(58) 即66,67,77,82,51,78,58
设一组初始关键字记录关键字为(19,15,12,18,21,36,45,10),则以19位基准记录的一趟快速排序结束后的结果为(10,15,12,18,19,36,45,21)
3. 快速排序不稳定quick sort排序算法之快速排序
快速排序的基本思想就是选取一个数作为基准【通常选择第一个元素或后一个元素】,将数据按照基准数据分为左右两部分,左边都比基准数据小,右边都比基准数据大,按照中间位置,递归左右两侧,直到只有一个数据时,排序完成。【 快速排序使用了分治的思想】【一趟排序结束都至少能够确定一个元素最终位置】
快递排序的递归次数与元素的初始排列有关。如果每一次划分后分区比较平衡,则递归次数少;如果划分后分区不平衡,则递归次数多。快速排序在最坏情况下的时间复杂度为O(n^2),时间复杂度均摊是(nlogn)。只有基准值处于每次的中间位置才是时间复杂度最好的。
快速排序的递归次数与分区处理顺序无关,即先处理较长的分区或先处理较短的分区都不影响递归次数。【可以形象地把快速排序的递归调用过程用一个二叉树描述,先处理较长或较短分区,可以想象为交换某一递归结点处的左右子树,这并不会影响树中的分支数。】
对关键码序列28,16,32,12,60,2,5,72快速排序(最常用的快速排序,以第一个关键码为基准),使用挖坑法,从小到大一次划分结果为((5,16,2,12)28(60,32,72))。
25,84,21,47,15,27,68,35,20进行排序时,变化为: 20,15,21,25,47,27,68,35,84, 15,20,21,25,35,27,47,68,84, 15,20,21,25,27,35,47,68,84的排序方法是(快速排序)
能说明快速排序是不稳定的排序方法的一组关键字序列是((20, 20,30,10,40) )
所谓的排序算法的稳定性是指序列中原本数值相同的元素在排序完成后,相同数值的元素的前后关系不变。所以,至少要含有相同的元素才可能出现不稳定的情况。 根据快排原理,当比对到10,则10与第一个20交换位置,则相对于第二个20发生了位置变化。所以不稳定。
在待排序的数据表已经为有序时,花费时间反而最多的是快速排序。 快排不适合对基本有序的数据集合进行排序。快排序越是无序效率越高。
有字符序列(Q,H,C,Y,P,A,M,S,R,D,F,X),新序列(F,H,C,D,A,M,P,S,R,Y,Q,X)是快速排序算法一趟扫描结果。
在快速排序中,要使最坏情况的空间复杂度为O(log2n )则要对快速排序作( 划分元素为三者取中 )修改。
最优的情况下空间复杂度为:O(log2n) ;每一次都平分数组的情况,基准数尽量为中间数。
为实现快速排序算法,待排序序列宜采用的存储方式是(顺序存储)。【顺序存储适用于频繁快速查询】
现有一数列{3, 2, 5, 7, 6, 8},要求按升序排序,下面说法正确的是:快速排序,每次选择最后一个元素作为支点,需要比较12次。
一组记录的排序码为(46,79,56,38,40,84),一趟排序的结果为(40,38,46,56,79,84),则采用的是(快速)排序算法。
快速排序只能使用递归方式实现 ❌【也可以使用非递归的方式】
序列{2,1,4,9,8,10,6,20}是某排序算法第二轮排序的结果,则该算法只能是快速排序。
原序列为{4,1,2,20,8,10,6,9} 第一趟快速排序:以4为轴值,最后得到 2,1,4,20,8,10,6,9 第二趟快速排序:以20为轴值,最后得到 2,1,4,9,8,10,6,20
快速排序算法是对一个list排序的最快方法
//这里的list指的是双向链表,因而用两个指针是可以操作的,这样也是比较快速的操作。线性排序(如基数排序、桶排序、计数排序是不适合的 ,元素不能快速移动) 冒泡排序需要大量移动元素,这是得不偿失的。 二分只适合顺序表。 综上:选择快速排序最好
快排的阶段性排序结果的特点是,第i趟完成时,会有i个以上的数出现在它最终将要出现的位置不可能是快速排序第2趟排序结果的是:3,2,5,4,7,6,9。
堆排序需要构建堆,所以比较次数多于快速排序。快速排序比较次数更少。
下列排序法中,元素的交换可能会出现新的逆序的排序方式是(快速排序)。
产生新的逆序对,并不是说逆序对的数目发生改变。稳定的排序算法,每交换一次,逆序对的数目必然发生改变。 冒泡每交换一次,会减少一个逆序对,并不会产生新的逆序对。 简单插入排序,若插入到已排序序列的最后,则不会产生新的逆序对。 简单选择排序,每次将一个元素归位。无论由小到大归位,还是由大到小归位,都不会产生新的逆序对。 而快排,是跳跃式交换,必然会产生新的逆序对。
4. 堆排序不稳定heap sort排序算法之堆排序
堆排序最坏为O(nlogn)
一趟排序结束都至少能够确定一个元素最终位置【堆排序属于选择排序,每次都将大根堆的根结点与表尾结点交换,确定其最终位置。】
基本有序的情况下:快排最慢,堆排最快。
要从1000个数据元素中选五个最小的,下面排序算法中,那个算法最快?堆排序
将整数数组(7-6-3-5-4-1-2)按照堆排序的方式原地进行升序排列,请问在整个排序过程中,元素3的数组下标发生过2次改变。 注:粉红色代表已经排好序的,绿色代表交换的节点,砖红色代表没做改动的点。 从图中可以看出来,3在交换4和交换5这两步中,位置都有变化,所以一共是2次 注意交换4这一步,本来交换之后,就是有序的,但是程序还会继续调整,直到所有节点调整完毕。
按整数数组的最大堆定义,每次调整完后根结点的元素与最后个元素交换,继续下次调整,直到所有的结点调整完毕。 原数组为 7 6 3 5 4 1 2 满足最大堆定义,直接交换根节点元素 2 6 3 5 4 1 7,交换完毕 6 5 3 2 4 1 7,调整完毕 1 5 3 2 4 6 7,交换完毕 5 4 3 2 1 6 7,调整完毕 1 4 3 2 5 6 7,交换完毕 4 2 3 1 5 6 7,调整完毕 1 2 3 4 5 6 7,交换完毕,此时虽然已有序,但仍需进行最大堆调整,因为最大堆算法时间复杂度为nlog2n,会进行继续搜索调整 3 2 1 4 5 6 7,调整完毕,移动一次 1 2 3 4 5 6 7,交换完毕,移动两次 2 1 3 4 5 6 7,调整完毕 1 2 3 4 5 6 7,交换完毕
数据表A中有10000个元案,如果仅要求求出其中最大的10个元素,则采用(堆排序)排序算法最节省时间。
从一个无序数组中挑选出其中前十个最大的元素,在以下的排序方法中最快的方法是堆排序。
堆排序平均执行的时间复杂度和需要附加的存储空间复杂度分别是(O(nlog(n))和O(1))。整个构建堆的时间复杂度为O(n)。
排序的方法有很多种,(堆排序)法是基于选择排序的一种方法,是完全二叉树结构的一个重要应用。
将一个从大到小的数组,用以下排序方法排序成从小到大的,(堆排序)最快。
在用堆排序算法排序时,如果要进行增序排序,则需要建立“大顶堆”。 堆排序在每一趟排序过程中,都会有一个元素被放置在最终位置上。
将整数数组(7-6-3-5-4-1-2)按照堆排序的方式原地进行升序排列,请问在第一轮排序结束之后,数组的顺序是6-5-3-2-4-1-7。
使用堆排序方法排序(45,78,57,25,41,89),初始堆为89,78,57,25,41,45。
堆是完全二叉树,根据父节点和子节点的关系,可以分为大根堆和小根堆。 大根堆的父节点比它的所有子节点大,小根堆的父节点比它的所有子节点小。 兄弟节点间不按大小排序。
堆通常用于获取最值。
用堆可以实现优先队列(priority_queue)
堆数据结构可以用数组方式存储。
对一个堆按层次遍历,不一定能得到一个有序序列。
值类型是在堆上分配的。
大根堆 对于大顶堆中的一组数据,单次操作一定可以获得这组数据的最大值。最大堆中插入一条数据的时间复杂度是O(log(n))。对于有n(n>3)个不重复元素的大顶堆,下标为n-2的元素和下标为n-1的元素的大小关系是无法判断。获取包含n个元素的大顶堆中的最小值,最多需要查找n/2次。可以用大顶堆实现快速从M个元素中查找最小的N个元素的算法。从M个元素中查找最小的N个元素时,使用大顶堆的效率比使用小顶堆更高。对于大顶堆中序列{64767,3444,4353,3344,45,2344,657,646},删除堆顶元素后,可得序列{4353,3444,2344,3344,45,646,657}。pop后,把堆尾元素顶上去,然后向下过滤节点
小根堆下列关键字序列中,序列{16,23,53,31,94,72}是堆。
下列关键码序列16,31,23,94,53,72是一个堆。
在一个小根堆中,从根结点到某个叶子结点所经路径上的结点构成一个递增有序序列。
删除最小元素的复杂度是o(logn)
查询最小元素的复杂度是o(1)
下标从1开始,在含有n个关键字的小根堆(堆顶元素最小)中,关键字最大的记录有可能存储在[n/2]+2位置上。
将一个元素插入大小为len的小顶堆中,最多需要移动log(len)次,最少需要0次。
已知关键字序列5,8,12,19,28,20,15,22是小根堆(最小堆),插入关键字3,调整后得到的小根堆是(3,5,12,8,28,20,15,22,19)。
插入关键字3时,先将其放在小顶堆的末端,再将该关键字向上进行调整。
关键码序列K = { 23 , 40, 28, 19, 20, 42 },经过筛选法建堆过程后,得到的最小堆为19,20,28,40,23,42。
按现有顺序先建堆,然后再调整。
对关键码集合K={22,11,38,68,43,6,10,48},用筛选法创建最小堆时,从关键码(68 )开始调整。
从下往上,从右到左的顺序,从第一个非叶结点开始调整。
5. 希尔排序不稳定shell sort排序算法之希尔排序
Shell排序,划分子序列做直接插入排序,所以和初始排列有关。
希尔排序是先分组,然后针对组内采取插入排序。
用希尔排序方法对一个数据序列进行排序时,若第1趟排序结果为9,1,4,13,7,8,20,23,15,则该趟排序采用的增量(间隔)可能是3。一趟排序结束后不一定能够选出一个元素放在其最终位置上的是希尔排序。【希尔排序每次是对划分的子表进行排序,得到局部有序的结果,所以不能保证每一趟排序结束都能确定一个元素的最终位置。】希尔排序最后一次的步长增量一定为1。希尔排序的组内排序采用的是直接插入排序。设 一组初始记录关键字序列为(50,40,95,20,15,70,60,45),则以增量d=4的一趟希尔排序结束后前4条记录关键字为(15,40,60,20)。已知步长为4 排序前: 50 40 95 20 15 70 60 45 排序后: 15 40 60 20 50 70 95 45
6. 冒泡排序稳定bubble sort排序算法之冒泡排序
冒泡排序的平均时间复杂度为O(n^2),最坏时间复杂度为O(n^2)
冒泡排序是相邻两两比较,把最大的顶上去,如果边上两个元素不是最值,肯定不是冒泡排序。
冒泡排序在初始关键字序列为逆序的情况下执行的交换次数最多。假设线性表的长度为n,则在最坏情况下,冒泡排序需要的比较次数为多少次?n(n-1)/2【逆序对的个数n(n-1)/2】对顺序表R{33,22,18,4,30,29,7,16,9,10}起泡排序,第三趟排序后,顺序表中的数据顺序是4,18,22,7,16,9,10,29,30,33。
对于每趟排序,从前往后遍历,如果当前位置的数比后面相邻位置的数大,则交换两个位置的数。 第一趟后:{22,18,4,30,29,7,16,9,10,33} 第二趟后:{18,4,22,29,7,16,9,10,30,33} 第三趟后:{4,18,22,7,16,9,10,29,30,33}
冒泡排序有一种优化方法,就是在每趟冒泡的时候都检测这次是否有交换元素的顺序,如果没有交换就说明序列是排好序的,下次就不用再冒泡了!所以和初始序列是有关系的。
设一组初始记录关键字序列(Q,H,C,Y,P,A,M,S,R,D,F,X),则按字母升序的第一趟冒泡排序结束后的结果是(H,C,Q,P,A,M,S,R,D,F,X,Y)
线性表的长度为10,在最坏情况下,冒泡排序需要比较次数为(45)。
9+8+……+1 = 45。
设有 1000 个基本有序的元素,希望用最快的速度挑选出其中前 10 个最大的元素,最好选用冒泡排序排序法。【因为只要前十个最大的,而且数据基本有序,所以此时不必要全部排序,用冒泡排序10趟就能将最大的10个上浮到最后面】【取最小的10个元素使用堆排序,取最大的10个元素使用冒泡排序】
7. [直接]选择排序排序算法之选择排序
简单选择排序,在待排序的数组中选出最小(或最大)的与第一个位置的数据交换,然后在剩下的待排序数组中重复找出剩余序列的最大(或最小)。关键字比较的次数与记录的初始排列无关。一趟排序结束都至少能够确定一个元素最终位置
选择排序每扫描一遍数组,只需要一次交换。
在选择排序中,数据已按升序排列和数据已按升降序排列俩者花费时间一样。
以下排序中平均时间复杂度最差的是选择排序。
归并排序 选择排序 希尔排序 堆排序
京东商城plus会员的消费记录金额分别为900,512,613,700,810,若采用选择排序算法对其进行从小到大的排序,第三趟排序结果为:512 613 700 900 810。
对关键字序列(33,12,44,10,6,8,17)进行选择排序:
8. [直接]插入排序稳定排序算法之插入排序
通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应的位置并插入的排序算法是插入排序。
设一组初始记录关键字的长度为8,则最多经过(7)趟插入排序可以得到有序序列。
在长度为n的顺序表的第i(1≤i≤n+1)个位置上插入一个元素,元素的移动次数为n-i+1。
对n个元素用插入法建堆的时间复杂度是O(nlog(n))。
对同一待排序序列分别进行折半插入排序和直接插入排序,两者之间可能的不同之处是元素之间的比较次数。
直接插入排序算法和初始排列有关,适用于待排序数据大部分已排序时。【在待排序的元素序列基本有序的前提下,效率最高。】某线性表中有100000个元素,其中前99990个元素递增有序,则采用(直接插入排序)方法进行递增排序时关键字比较次数最少。在最好情况下,直接插入排序排序算法时间复杂度最低。已知数据表A中每个元素距其最终位置不远,为节省时间排序,应采用直接插入排序。下列排序算法中,某一趟结束后未必能选出一个元素放在其最终位置上的是直接插入排序。
插入排序方法可能出现这种情况:在最后一趟开始之前,所有的元素都不在其最终应在的正确位置上。【最小的元素在最后一个位置时将出现这种情况】
在对一组记录(54,38,96,23,15,72,60,45,83)进行直接插入排序时,当把第7个记录60插入到有序表时,为寻找插入位置需比较(3)次。
某学生信息表,设一组表示成绩的关键字序列(24,15,32,28,19,10,40)采用直接插入排序时,当插入记录19到有序表时,为找插入位置需比较次数为4。
对记录(54,38,96,23,15,72,60,45,83)进行直接插入排序时,当把第八个记录45插入到有序表时,为找到插入位置需比较(5)次。
由插入排序算法,当要插入第八个元素时,前七个元素已经有序为: 15 23 38 54 60 72 96 第八个记录45从后向前比较到38时,45>38,找到了前八个元素有序应该放的位置,停止循环,从96到38,共比较了5次。 这题直接数前面有几个比它自己大的数然后 +1 就好了。插入排序从后往前比。
设有一组初始关键字序列为(30,20,10,25,15,28),则第4趟直接插入排序结束后的结果的是10,15,20,25,30,28。
对数据序列{ 15,9,7,8,20,-1,4 }进行排序,进行一趟后数据的排序变为{ 9,15,7,8,20,-1,4 } ,则采用的是(直接插入排序 )算法。
如果开发一款打扑克的游戏,现在要对选手拿到的牌进行排序,请问一下哪种排序方式最合适?插入排序。幼儿园老师挑一组同样花色的扑克牌,让小朋友按牌面数字大小排成一列,小朋友依次从左到右找到合适位置放入扑克牌、这种方法类似以下哪种算法(插入排序)体育课的铃声响了,同学们都陆续地奔向操场,按老师的要求从高到矮站成一排。每个同学按顺序来到操场时,都从排尾走向排头,找到第一个比自己高的同学,并站到他的后面,这种站队的方法类似下列哪种算法:插入排序。 字符序列(‘D’, ’Q’, ‘U’, ‘I’, ‘A’, ’N’)只能是插入排序算法两趟排序后的结果。若数据元素序列(11,12,13,7,8,9,23,4,5)是采用下列排序方法之一得到的第二趟排序后的结果,则该排序算法只能是(插入排序)。假设小明用某个排序算法对整数序列(82,45,25,15,21)进行排序。以下为排序过程中序列状态的变化过程: 输入:82 45 25 15 21 第一步:45 82 25 15 21 第二步:25 45 82 15 21 第三步:15 25 45 82 21 ······ 请问小明用的是什么排序算法?插入排序
9. 计数排序排序算法之计数排序
计数排序的时间复杂度为O(n+k) 计数排序的空间复杂度为 O(k) 计数排序是一种基于 统计 的排序算法