数据结构与算法 | 青训营笔记

113 阅读3分钟

这是我参与「第三届青训营 -后端场」笔记创作活动的第4篇笔记

1:经典排序算法

(1)插入排序

步骤:

1.从第一个元素开始,该元素可以认为已经被排序

2.取下一个元素a,从已排序的元素序列从后往前扫描

3.如果该元素大于a,则将该元素移到下一位

4.重复步骤3,直到找到已排序元素中小于等于a的元素

5.a插入到该元素的后面,如果已排序所有元素都大于a,则将 a插入到下标为0的位置

6.重复步骤2~5

缺点: 平均和最坏的时间复杂度高达O(N*N);

优点: 最好情况的时间复杂度为O(N);

(2)快速排序

步骤:

(1)首先设定一个分界值,通过该分界值将数组分成左右两部分。 

(2)将大于或等于分界值的数据集中到数组右边,小于分界值的数据集中到数组的左边。此时,左边部分中各元素都小于分界值,而右边部分中各元素都大于或等于分界值。

(3)然后,左边和右边的数据可以独立排序。对于左侧的数组数据,又可以取一个分界值,将该部分数据分成左右两部分,同样在左边放置较小值,右边放置较大值。右侧的数组数据也可以做类似处理。 

(4)重复上述过程,可以看出,这是一个递归定义。通过递归将左侧部分排好序后,再递归排好右侧部分的顺序。当左、右两个部分各数据排序完成后,整个数组的排序也就完成。

缺点:

最坏的情况是,每次所选的中间数是当前序列中的最大或最小元素,这使得每次划分所得的子表中一个为空表,另一子表的长度为原表的长度-1。这样,长度为n的数据表的快速排序需要经过n次划分,使得整个排序算法的时间复杂度为O(n2)。

优点:

平均情况整个算法的时间复杂度为O(nlog2n)。

(3)堆排序

操作:

最大堆调整:将堆的末端子节点作调整,使得子节点永远小于父节点

创建最大堆:将堆中的所有数据重新排序

堆排序:移除位在第一个数据的根节点,并做最大堆调整的递归运算

缺点:

最好情况的时间复杂度为O(n*logn)

优点:

最坏的情况时间复杂度为O(n*logn)

总结:插入算法在短序列中速度最快;快速排序在其他情况中速度最快;堆排序不同情况下区别不大。

2:pdqsort

(1)简介

Pattern-defeating quicksort,是一种新型的排序算法,将随机快速排序的快速平均情况与堆排序的最坏情况快速组合在一起,同时在具有特定模式的输入上实现了线性时间。 pdqsort是David Mussers introsort的扩展和改进。

(2)结合三种排序算法的优点

对于短序列(小于一定长度)我们使用插入排序;其他情况下使用快速排序来包证整体性能;当快速排序不能很好发挥作用时,使用堆排序来保证最坏情况和最好情况一样。

(3)如何让pdqsort速度更快

尽量使快速排序的pivot为序列的中位数-->改进choose pivot

(4)优化-Pivot的选择

短序列(<=8),选择固定元素;

中序列(<=50),采样三个元素

长序列(>50),采样九个元素

(5)优化重复元素很多的情况

如果两次partition生成的pivot相同,即partition进行了无效分割,此时认为pivot的值为重复元素。当检测到此时的pivot和上次的相同时(发生leftSubArray),使用partitionEqual将重复的元素排列在一起,减少重复元素对于pivot选择的干扰