排序算法
冒泡排序优化:
- 每轮交换后,下一轮的交换次数减一。
- 记录每轮交换后最后一次交换的索引,在这之后的都已排序好。如果索引为零,代表未发生交换,已排好序。
选择排序:
将集合分为两个部分:有序和无序,每次排序选择无序部分中的最小/大值放入有序集合中,每次排序只需要交换一次。
一般来说,对于有序度低的集合,选择排序快于冒泡排序,因为交换次数少,但是选择排序不稳定,会改变原集合中相同元素的位置,而冒泡排序是稳定的。
插入排序
初始时,将集合第一个元素当作有序,往后扩展有序的范围,依次往后面进行比较,将被比较的元素插入合适的位置,其他的元素往后移,因为它没有改变原集合中相同元素的位置,所以它也是稳定的。
一般来说,插入排序的性能优于选择排序,假设情景为从扑克牌堆中取牌,对于插入排序,你手中的牌就相当于有序区间,而选择排序需要在牌堆中找最小/大值。同时,由牌堆的例子可以看出,插入排序可以在排序的同时插入新的数据,而选择排序需要排序前就把所有数据给好。
快速排序
1. 单边排序(lomuto洛穆托分区方案)
- 选择最右元素作为基准点元素
- j 指针负责找到比基准点小的元素,一旦找到则与 i 进行交换
- i 指针维护小于基准点元素的边界,也是每次交换的目标索引
- 最后基准点与 i 交换,i 即为分区位置
- 修改上下索引边界,递归调用
2. 双边排序
- 选择最左元素作为基准点元素
- j 指针负责从右向左找比基准点小的元素,i 指针负责从左向右找比基准点大的元素,一旦找到,二者交换,直至 i,j 相交
- 最后基准点与 i(此时 i 与 j 相等)交换,i 即为分区位置
注意:
- 一定是j先动,如果i先动,最后i与j重合的时候指向的指就会比基准点大
- 内层循环一定要加上i<j,如果不加,对于j前面的值都比基准点小的情况下,i就会大于j,导致基准点交换后左边会有一个值大于基准点
2.特点:
- 平均时间复杂度O(nlog2n),最坏时间复杂度O(n²)
- 数据量较大时,优势非常明显
- 属于不稳定排序
评论