1参考图解排序算法之冒泡排序 (qq.com)
对于数组呢,排列的是五花八门的,但是总有可能出现还没排序的时候人家就是有序数组,还有可能呢是第一层 for 循环遍历了一半数组就变得有序了,那这些情况有序了我们就不用再比较了,浪费时间。
如何知道有序呢:第二层 for 循环的时候,没有交换的元素。增加一个 flag 数组,如果第二层循环没有交换元素的时候,证明数组已经排序好了,不需要再继续遍历,直接返回。
2参考图解排序算法之选择排序 (qq.com)
选择排序,从数列中选出最小(大)的元素,放在序列起始位置,接着在未排序序列中找出最小(大)元素,放已排序序列的末尾。选择排序不稳定(稳定是不会改变相同元素的相对位置)。
3参考图解排序算法之插入排序 (qq.com)
选择待排序序列的第 1 个元素作为有序序列,将剩余元素当作未排序序列;
从未排序序列中选择第 1 个元素,与有序序列中的元素依次比较,将其插入到合适的位置(通过这个可以看出插入排序稳定的特性);
重复上一步,直至未排序序列无元素可进行插入时,停止操作,此时序列全部有序。
4参考图解排序算法之希尔排序 (qq.com)
希尔排序,又叫缩小增量排序,是一种改进的更高效的插入排序
首先确定数组元素的间隔(gap)值,一般 gap = length/2;
将数组元素按照 gap 从第 1 个元素开始分成若干个子数组(即位置相隔为 gap 的元素为一个子数组),分别对各子数组进行直接插入排序(可以看出希尔排序不稳定);
减小 gap 值,一般 gap = gap/2,并重新将整个数组按照新的 gap 值分成若干个子数组,并分别对各子数组进行直接插入排序,直至 gap = 1,排序结束。
当gap=1就是直接插于排序
以上四种都是时间复杂度,空间复杂度
5参考图解排序算法之快速排序 (qq.com)
快速排序(QuickSort),又叫分区交换排序,简称快排,它是对冒泡排序的一种改进,运用了分治算法
挑数。从数组中挑选出一个元素,这个元素叫“基准(pivot)”(为了方便,一般选择第 1 个元素)
划分。将数组划分成两部分,将待排序数组中小于 pivot 的数移动到左边,将大于 pivot 的数移动到右边,这时两部分子数组的元素相对有序。(这个操作也叫“分区(partition)”操作,如果是等于 pivot 的数可以放在任何一边,可以看出快速排序不稳定这个特性,无法保证相等的数据按初始的位置存放)
求解。将两个分区的元素按照第 2 步的方式继续对每个分区找出 pivot,然后移动,直至每个分区只有 1 个元素为止。
主要使用双指针法,选择第 1 个元素作为 pivot,双指针 i 和 j 分别指向数组最左边和最右边,j 从右向左找比 pivot 小的数,i 从左向右找比 pivot 大的数,然后交换,因为 pivot 一般选取的是最左边的值,所以是 j 先移动
时间复杂度~
,空间复杂度
~
6参考图解算法之归并排序 (qq.com)
归并排序(MergeSort),对于待排序数组,将其从中间位置分为前后两个部分,对两部分分别排序,将两个已经排序的子数组合并成一个数组,这样达到数组整体有序。
划分(Divide)将待排序数组分为两个均等的子数组;
求解(Conquer)分别对两个子数组进行排序(即对两个子数组递归执行归并排序)(终止就是将每个子数组拆分成只剩下一个元素的时候);
合并(Combine)将两个已经排序的子数组合并成一个完整的有序数组,得到最终结果(在合并过程中,如果是元素数值相同,则不会改变位置,所以归并排序是稳定的排序算法)
时间复杂度是,空间复杂度
7参考图解排序算法之堆排序 (qq.com)
堆排序是选择排序的优化。堆默认是一棵完全二叉树,而且每一个节点的值都必须大于等于(或者小于等于)其子树中每个节点的值。将数组构造成一个大顶堆或者小顶堆,每次取走堆顶元素,再将剩下的堆调整为大顶堆或者小顶堆。
构建堆。将待排序数组构造成一个大顶堆(或者小顶堆);(使用的是数组,而不是二叉树,我们可以把数组的样式想成是一棵二叉树)
堆排序。将堆顶元素取出(大顶堆为最大值,小顶堆为最小值),将其与末尾元素进行交换,此时末尾元素就成了最大值(或者最小值);(在交换数据的时候是栈顶元素和末尾元素交换,可能存在改变相同的值相对位置的情况,所以堆排序不是稳定的排序算法)
调整堆。将剩余元素重新构成一个堆,重复第 2 步,交换堆顶元素与当前末尾元素,最终使得整个数组有序,得到一个有序数组
时间复杂度是,空间复杂度是
8参考图解排序算法之桶排序 (qq.com)
“桶”是指一种数据结构,代表一个区间范围,用于临时存储排序元素。桶排序(BucketSort),一种分布式排序算法,将待排序数组元素分到有限数量的桶里,每个桶里的数据分别进行排序, 按照桶的顺序将元素合并成有序数组
初始化 m 个桶,将 n 个元素分配到 m 个桶中;(分配的规则有很多,为了好理解,我在本文使用待排序元素整除的方式,这样可以将元素较为均匀的分配到各个桶中,比如每个元素值 / 10 来分配桶)
对每个桶内的数据分别进行排序,这里可以借助任意排序算法;(桶排序是否稳定取决于这里借助的排序算法,比如你选择的如果是插入排序,那桶排序就是稳定的,比如你选择的是堆排序,那这个时候的桶排序就不是稳定的)
按照桶的从大到小的顺序,将所有元素合并成有序数组
时间复杂度分为两部分:1将 n 个待排序元素分配到 m 个桶中,平均每个桶中有 n / m 个元素,这需要从左到右遍历数组,时间复杂度为 O(n);2每个桶内再次排序的时间总和
桶排序中,需要创建 m 个桶的额外空间,空间复杂度为 O(m),此外创建了长度为 n 的 res 数组存储排序后的数组,空间复杂度为 O(n),所以总的空间复杂度为 O(n + m)
桶排序的效率依赖于桶的选择和数据的分布情况,主要适用于两个场景:1. 待排序数组的元素分布均匀,这样可以使桶排序发挥出更好的性能;2. 应用于外部排序,当待排序数组的数据量特别大,无法一次性的加载到内存中,可以将数据分到多个桶里,在内存中逐个读取并排序每个桶,最后将每个桶的数据写回到外部存储中