前言
本章对常用的排序算法做个系统的回顾与总结。
冒泡排序
基本思路:每次遍历,两两比较,确定一个位置的值
平均时间复杂度:O(n^2)
是否稳定:是
1 | public void algorithmTest() { |
选择排序
基本思路:每一次遍历,确定一个位置的数据
平均时间复杂度:O(n^2)
是否稳定:否
1 | private void chooseSort(List<Integer> chooseList) { |
插入排序
基本思路:将第一个元素看作一个已经排好序的序列,从第二个元素开始,依次按顺序插入序列中。
平均时间复杂度:O(n^2)
是否稳定:是
1 | private void insertSort(List<Integer> insertList) { |
快速排序
基本思路:
- 先设定一个基准值(可以是首位,也可以是随机一个),然后从末尾向首位遍历,遇到比基准小的
便移往左边,再然后从首位向末尾遍历,遇到比基准大的便移往右边。最后得到基准值的下标 - 以基准值下标为界,分为左右两部分,继续按照1中的逻辑分别继续递归处理
平均时间复杂度:O(NlogN)
是否稳定:否
1 | public void algorithmTest() { |
归并排序
基本思路:
- 将每一个元素看做一个有序序列
- 将这些有序序列两两合并形成新的有序序列
- 依次执行直到最终合并成一个有序序列
平均时间复杂度:O(NlogN)
是否稳定:是
1 | private void mergeSort(List<Integer> mergeList) { |
堆排序
堆的定义:用数组实现的二叉树,分为最大堆,最小堆两类。
在最大堆中,父节点的值比每一个子节点的值都要大;而在最小堆中,父节点的值比每一个
子节点的值都要小。
因此,最大堆的根节点既是数组中的最大值,同样,最小堆的根节点就是其最小值。
基本思路:
- 利用堆的特性,首先将无序序列构建成一个堆,得到其最大|最小值
- 将根节点与序列队尾置换
- 抛开队尾元素,调整序列使其重新成为一个堆,然后重复2,3步骤
平均时间复杂度:O(NlogN)
是否稳定:否
1 | private void heapSort(List<Integer> heapList) { |
希尔排序
基本思路:希尔排序是基于插入排序做的优化,插入排序在序列基本有序的前提下性能会大大提升。
所以希尔排序的思路就是一步步使得序列基本有序。
- 定义一个增量,如size/2,根据增量将序列分为n个序列
- 对每个序列做插入排序
- 按照计算方式,缩小增量,然后重复步骤2,直到增量为1,形成一个序列
4 .对最后一个序列做插入排序,因其基本有序,性能会大大提高
平均时间复杂度:受增量影响
是否稳定:否
1 | private void shellSort(List<Integer> shellList) { |
总结
排序算法最关注的应该是时间复杂度了,在对排序算法的选择上,当然是优先选择更快的算法。
在没有要求稳定的情况下,快排是第一选择。
冒泡,选择,插入三种排序应该避免使用,因为有更好选择。
归并排序由于其空间要求,所以需要考虑实际应用中内存空间的占用。可以作为在要求稳定情况
下的快排的替代。
希尔排序基于插入排序的优化,可以满足一般情况下的需求,而且相对快排实现更简单。