快速排序
快速排序的基本思想是:通过一趟排序将待排的序列划分为独立的两个部分,其中一部分序列的元素均不大于另一部分记录的关键字,然后再分别对这两部分序列继续进行快速排序,以达到整个序列有序。
大致步骤如下:
- 首先设置一个分界值也就是基准值又是也称为监视哨,通过该分界值将数据分割成两部分。
- 将大于或等于分界值的数据集中到右边,小于分界值的数据集中到左边。一趟排序过后,左边部分中各个数据元素都小于分界值,而右边部分中各数据元素都大于或等于分界值,且右边部分个数据元素皆大于左边所有数据元素。
- 然后,左边和右边的数据可以看成两组不同的部分,重复上述1和2步骤,当左右两部分都有序时,整个数据就完成了排序。
首先设置三个参数,first指向区间左端,last指向区间右端,key为当前的分界值。从待排序的数据元素中选取一个通常为第一个作为基准值元素(key)key=num[o],设置双指针first指向区间左端,last指向区间右端;
key首先与num[last]进行比较,如果num[last]<key,则num[[first]=num[last]将这个比key小的数放到左边去,如果num[last]>=key则–last,再拿num[last]与key进行比较,直到num[last<key交换元素为止。
num[last<key交换元素后,转向左边部分,用num[first]与key进行比较,如果num[first]<key,则++first,然后继续进行t比较,直至num[[first]>=key,则num[last]=num[[first]。
重复这个操作
第一轮排完后,23左侧的数据比23小。23右侧的数据比23大。然后将23左侧的数据进行快排,右侧的数据也进行快排
第一趟的完整示例图:
第一趟排序结束,得到[2,11,15,20,9,5]23[56,45,35]然后对左右子数列进行同样的操作。
2[11,15,20,9,5]23[35,45]56
2[5,9]11[20,15]23354556
25911152023354556
完成从小到大的排序
归并排序
非常浪费空间
归并排序是建立在归并操作上的一种有效、稳定的排序算法,该算法采用非常经典的分治法(分治法可以通俗的解释为:把一片领土分解,分解为若干块小部分,然后一块块地占领征服,被分解的可以是不同的政治派别或是其他什么,然后让他们彼此异化),归并排序的思路很简单,速度呢,也仅次于快速排序,接下来我们详细的看看归并排序的过程。
基本思路:
- 第一步:将序列中待排序数字分为若干组,每N个数字分为一组。二路归并就是两个数字为一组
- 第二步:把每个组里的元素进行排序,然后将若干组两两合并,保证合并的组都是有序的。
- 第三步:重复第二步的操作,直到剩下最后一组即为有序数列。
一般归并排序都是用来合并多个线性表的,对单列数据,二路归并排序可以对元素进行两两合并,示例如下:
对第三次归并,将52与28比较,28小,放入新表头,52再与33比较,33放入新表,52再与72比较,52放入新表,57再与72比较,57放入新表…
基数排序
由上图可知,基数排序是基于多个关键字来进行多轮排序的,本质也是将问题细分,如上右图例子,分别按个位、十位、百位的大小作为关键字进行了三轮排序,最终得出结果。
总结
记住下面的表格,选择题70%-80%能拿分
1)冒泡排序,选择排序,插入排序:两层嵌套循环就能完成。所以平均时间复杂度和最坏情况都是O(n2)。插入排序和冒泡排序在几乎有序的的情况下,效率能大幅度提升,最好的情况是O(n)。都是只涉及两两元素进行交换,所以只要申请一个临时空间就够了即空间复杂度为O(1),而且不需要额外申请空间
2)基数排序:是根据元素个位、十位、百位、千位…位数进行申请空间,所以k就是位数所申请的数量。平均时间复杂度,最坏和最好情况都是O(n*k)。空间复杂度是O(n+k)。需要额外申请内存空间
3)希尔排序,归并排序,快速排序,推排序:平均时间复杂度和最好情况都是O(n log n)。最坏的情况:快速排序在几乎有序的情况下是最坏的情况O(n2)。空间复杂度:希尔排序和推排序只申请了一个内存,归并排序需要申请很多个单独的空间存放两两比较之后的元素所存的位置,空间复杂度是最高的
前面已经介绍过,稳定性就是相等的两个元素的相对位置在排序前后保持不变。
空间复杂度中,大部分排序都是比较交换,无需多余空间,快速排序则是需要存储每次的基准值,归并排序需要一个新表,基数排序需要新表,还需要存储关键字的空间。
时间复杂度中,与堆、树、二分有关的算法都是nlogn,直接的算法都是nn(包含了两重嵌套循环。内循环会随着输入规模的增加而执行n次,而外循环也会执行n次。因此,总的操作次数将是n乘以n,导致时间复杂度为O(m2),分析算法原理都可以轻易得出上述结论。
练习题
【2020】对个数排序,最坏情况下时间复杂度最低的算法是()排序算法。
(A)插入
B)冒泡
©归并
(D)快速
答案:C
【2020】根据渐进分析,表达式序列:n4,logn,2n,1000n,n2/3,n!从低到高排序
为()。
(A)logn,1000n,n213,n4,n!,2n
(B)n23,1000n,logn,n4,n,2n
©logn,1000n,n213,2n,n4,n!
(D)logn,n213,1000n,n4,27,n!
答案D
常量*n:通常常量可以去掉,因为n足够大的情况下常量就没有什么含义了。
【2021】对数组A=(2,8,7,1,3,5,6,4)构建大顶堆为()
(A)(1,2,3,4,5,6,7,8)
(B)(1,2,5,4,3,7,6,8)
©(8,4,7,2,3,5,6,1)
(D)(8,7,6,5,4,3,2,1)
答案C,构建大顶堆不是完成排序
【2021】对于一个初始无序的关键字序列,在下面的排序方法中,()第一趟排序结束后,一定能将序列中的某个元素在最终有序序列中的位置确定下来。
①直接插入排序②冒泡排序③简单选择排序④堆排序⑤快速排序⑥归并排序
(A)①②③⑥
(B)①②③⑤⑥
©②③④⑤
(D)③④⑤⑥
答案C