排序
- 直接插入排序:选取无序区的一个元素找到在有序区的插入位置,插入有序区(排扑克牌的过程)
平均时间复杂度:O(n^2)
空间复杂度:O(1)
稳定性:稳定
1 | /** |
2. 希尔排序(缩小增量法):(直接插入排序优化)先选定一个整数gap(步长),把待排序序列中所有元素(n个)分成gap个组,所有距离为gap的元素分在同一组内,并对每一组内的元素进行直接插入排序。然后将gap逐渐减小,重复上述分组和排序的工作,当到达gap=1时,排序前的数据已将近正序,所有元素在统一组内排好序,gap=0时结束。(效率高于直接插入排序,但不稳定)
- 平均时间复杂度:O(nlogn)
- 空间复杂度:O(1)
- 稳定性:不稳定
取gap=n/2为例:
1 | public void shellSort(int[] arr) { |
3. 冒泡排序:每一轮从头开始,从前往后两两元素进行比较,前一个比后一个大就交换,直到将最大的元素交换到末尾位置,每轮减少一个元素
- 平均时间复杂度:O(n^2)
- 空间复杂度:O(1)
- 稳定性:稳定
1 | /** |
4. 快速排序:基于分治思想排序,将某元素作为基准值,把比基准值小的调整到基准值左边,递归切分基准值左右两部分,按同样规则进行调整
- 平均时间复杂度:O(nlogn)
- 空间复杂度:O(logn)
- 稳定性:不稳定
调整具体思路是:
- 选定一个基准值(为了方便选区间最左边那个)
- 确定两个指针 l 和 r,分别从区间两边向中间走,r指针找比基准值小的,l指针找比基准值大的,指针移动时,让r指针先走
- 两指针停下后交换对应位置的值
- 继续向下走,重复以上步骤,直到两指针重合时,最后将基准值与重合位置值进行交换。
为什么要让r指针先走?
最后是要把相遇位置处的数和基准位置处的数进行交换,要保证交换到基准值位置的数比基准值小,如果让l指针(找大的)先走,l指针先停下,两指针相遇时会找到一个比基准值大的数和基准值交换,所以得让r指针(找小的)先走
[6,1,2,7,9,3,4,5,10,8]调整过程:
完整快速排序过程:
1 | /** |
5. 选择排序:每轮在区间中选择一个最小的排在该轮区间最前面
- 平均时间复杂度:O(n^2)
- 空间复杂度:O(1)
- 稳定性:不稳定
1 | /** |
6. 堆排序:每轮将待排的无序序列调整成堆结构,将堆顶最值交换到最后,每轮减少一个元素
- 基本思路:
- 升序采用大顶堆(由于大根堆每轮最大的会被交换到最后,形成升序序列),降序采用小顶堆
- 首先将待排序的数组调整成一个堆(大根堆/小根堆),此时,整个数组的最大(小)值就是堆顶
- 将堆顶元素与末尾的元素交换,此时,末尾的元素为最大(小)值,剩余待排序序列个数为n-1个
- 将剩余的n-1个数再调整成堆(大根堆/小根堆),由于交换后只有堆顶元素不符合堆结构,所以对堆顶元素执行下潜即可,再将堆顶元素与n-1位置的元素交换,如此反复执行,便能得到有序序列
- 平均时间复杂度:O(nlogn)
- 空间复杂度:O(1)
- 稳定性:不稳定
堆:一种完全二叉树
- 大顶堆:每个父结点的值都大于其左右孩子的值
- 小顶堆:每个父结点的值都小于其左右孩子的值
数组表示:
数组中某个元素的父结点及其左右孩子索引:
- 父节点索引为i
- 左孩子索引:2*i+1
- 右孩子索引:2*i+2(左孩子索引+1)
- 孩子索引为j
- 父节点索引:(j-1)/2
- 最后一个非叶子结点索引:数组长度/2-1
1 | /** |
7. 归并排序:基于分治思想的排序算法
- 思想
- 分:切分原始数组(向下)
- 治:两子序列合并成有序序列
- 合:有序序列继续和其他序列合并(向上)
- 平均时间复杂度:O(nlogn)
- 空间复杂度:O(n)
- 稳定性:稳定
1 | /** |
8. 计数排序:使用一个count[]数组来统计原数组每个元素出现的个数,count数组值作为元素个数值,索引作为元素值(索引和元素值之间的关系为相对值,不一定与元素值相等,建立一种映射关系),再根据个数把对应元素写回原数组
- 平均时间复杂度:O(n+k) (k为count[]大小,n元素个数)
- 空间复杂度:O(k)
- 稳定性:可稳定或不稳定
1 | /** |
1 | /** |
9. 桶排序:将数组元素分散到多个桶,保证索引小的桶装小的元素,索引大的桶装大的元素,然后进行桶内排序后,接着按顺序取桶,最后把桶内元素写回原数组
- 平均时间复杂度:O(n+k) (k为桶个数,n为元素个数)
- 空间复杂度:O(n+k)
- 稳定性:稳定
1 | /** |
1 | /** |
10. 基数排序:以下采用LDS,即从个位开始,从右向左对每一位进行排序。初始化[0 ~ 9]个桶,刚开始按个位大小将每个元素分散到对应的桶(个位为0的装入0号桶,以此类推),个位分散完之后,再按桶顺序取出元素写回原数组,再进行下一轮百位的排序,以此类推。
- 平均时间复杂度:O(k*n) (k位数,n元素个数)
- 空间复杂度:O(m) (m桶个数)
- 稳定性:稳定
1 | /** |
java中Arrays.sort()根据数据量不同和特性采用不同排序算法。
- 本文作者: zzr
- 本文链接: http://zzruei.github.io/2023/02b9b1def2.html
- 版权声明: 本博客所有文章除特别声明外,均采用 Apache License 2.0 许可协议。转载请注明出处!