十大排序算法
不值钱
冒泡排序
默认以升序排列(从小到大)
冒泡排序就是从第一个开始将相邻的两个进行排序,大的往后移动,然后继续向右进行比较,直到和最后一个比较完,然后又从第一个开始,重复上面的操作,直到倒数第二个,因为最后一个在第一次比较的时候以及确认是最大的了,就这样每轮比较确定一个数据,知道所有数据全部确定。
如果后面的数字没有任何交换,那么这个数组就是有序的。
- 平均时间复杂度:O(n^2)
- 最好情况:O(n)
- 最坏情况:O(n^2)
- 空间复杂度:O(1)
- 排序方式:In-place
- 稳定性:稳定
举个例子:
现在有一个数组要排序:1 ,3, 5, 4, 9, 8, 6
第一轮:1, 3, 4, 5, 8, 6, 9
第二轮:1, 3, 4, 5, 6, 8, 9
第三轮:1, 3, 4, 5, 6, 8, 9
选择排序
选择排序就是默认第一个数字就是最大的数字,将其作为参照物,然后依次和后面的数字进行比较
如果后面的数字大于参照物,那么就以这个数字作为参照物,最后将参照物对应的位置和最后一个数字进行交换,此时最后一个数字就是最大的拿个数字,同理继续以第一个数字为剩下数字中的最大值,进行上面的比较,此时最后一个数字不参加比较,最后将参照物对应的位置和倒数第二个数字进行交换,这样第二大的数字就确认了,按照上面的方法一直比较直到排序好
- 平均时间复杂度:O(n^2)
- 最好情况:O(n^2)
- 最坏情况:O(n^2)
- 空间复杂度:O(1)
- 排序方式:In-place
- 稳定性:不稳定
举个例子:
现在有一个数组要排序:1 ,3, 5, 4, 9, 8, 6
第一轮:1, 3, 5, 4, 8, 6, 9
第二轮:1, 3, 5, 4, 6, 8, 9
第三轮:1, 3, 4, 5, 6, 8, 9
第四轮:1, 3, 4, 5, 6, 8, 9
第五轮:1, 3, 4, 5, 6, 8, 9
第六轮:1, 3, 4, 5, 6, 8, 9
插入排序
从小到大排序
插入排序就是从第二个数开始和左边的数据进行比较,直到左边比自己小就停止,把数据插入到这个小的数据后面,然后从第三个数字开始和左边比较直到左边小于自己就停止,把数据插入到这个小数后面,同理进行比较直到最后,这样在比较的时候就能确保左边的数据是有序的且从小到大排序好了。
- 平均时间复杂度:O(n^2)
- 最好情况:O(n)
- 最坏情况:O(n^2)
- 空间复杂度:O(1)
- 排序方式:In-place
- 稳定性:稳定
举个例子:
现在有一个数组要排序:1 ,3, 5, 4, 9, 8, 6
第一轮:1 ,3, 5, 4, 9, 8, 6
第二轮:1 ,3, 5, 4, 9, 8, 6
第三轮:1, 3, 4, 5, 9, 8, 6
第四轮:1, 3, 4, 5, 9, 8, 6
第五轮:1, 3, 4, 5, 8, 9, 6
第六轮:1, 3, 4, 5, 6, 8, 9
进阶型
希尔排序
希尔排序就是将数据递归分组,首先分为长度/2(值为x)组
然后将第一个数字与1+x进行插入排序,经过第一次在整体排序后,小的数字很快会被移动到前面
重新将数据分组,原来的组数/2
小的数字很快会被移动到前面
- 平均时间复杂度:O(n log n)
- 最好情况:O(n log^2 n)
- 最坏情况:O(n log^2 n)
- 空间复杂度:O(1)
- 排序方式:In-place
- 稳定性:不稳定
举个例子:
现在有一个数组要排序:1 ,3, 5, 4, 9, 8, 6
第一轮:首先分为4组1, 9 3, 8 5, 6 4
排序后 1, 9 3, 8 5, 6 4
结果:1 ,3, 5, 4, 9, 8, 6
第二轮:然后分为两组,每组相隔2个数字1, 9 , 5, 6 3, 8, 4
排序后1, 5, 6, 9 3, 4, 8
结果:1, 3, 5, 4, 6, 8, 9
第三轮:然后分为1组,每组相隔1个数字1, 3, 5, 4, 6, 8, 9
排序后1, 3, 4, 5, 6, 8, 9
结果:1, 3, 4, 5, 6, 8, 9
堆排序
堆排序是一种基于数的排序算法
把数据以完全二叉树的形式连接起来(乱序)
我们通过一定节点达到二分查找数的结果
二分查找树
- 任意节点
- 最多有两个子节点
- 左面的节点都小于父节点
- 右面的节点都大于父节点
然后在写结果的时候就想从树的上面光照投影一样把投影从左到右读就行了
- 平均时间复杂度:O(n log n)
- 最好情况:O(n log n)
- 最坏情况:O(n log n)
- 空间复杂度:O(1)
- 排序方式:In-place
- 稳定性:不稳定
常用型
快速排序
快速排序的三种类型
- 挖坑法
- 左右法
- 前后法
快速排序就是选择一个数字作为参照物(基准数字),然后和另一个的进行比较,如果是右边的小于参照物就交换,参照物左面的大于参照物就交换
整体排序之后,参照物的位置是正确的,左右两个是无序
将左右两个都当做一个新序列进行排序基准数
- 平均时间复杂度:O(n log n)
- 最好情况:O(n log n)
- 最坏情况:O(n^2)
- 空间复杂度:O(1)
- 排序方式:In-place
- 稳定性:不稳定
现在有一个数组要排序:1 ,3, 5, 4, 9, 8, 6 假定我们选择6为参照物
第一轮:1 ,3, 5, 4, 9, 8, 6
第二轮:1 ,3, 5, 4, 9, 8, 6
第三轮:1, 3, 4, 5, 9, 8, 6
第四轮:1, 3, 4, 5, 9, 8, 6
第五轮:1, 3, 4, 5, 8, 9, 6
第六轮:1, 3, 4, 5, 6, 8, 9
归并排序
让两个有序队列进行比较,然后每个队列依次取出1个数字比较,然后小的数字被去除
-
分割
- 依次将数列二等分,二等分之后的子序列继续二等分
- 直到每个子序列只有一个数字,停止分割
-
合并
-
按照分割的顺序进行合并
初始: 5 2 4 6 1 7 8 3 分解:5 2 4 6 1 7 8 3 5 2 4 6 1 7 8 3 解决:5 2 4 6 1 7 8 3 2 5 4 6 1 7 8 3 合并:2 4 5 6 1 3 7 8 终止: 1 2 3 4 5 6 7 8
- 平均时间复杂度:O(n log n)
- 最好情况:O(n log n)
- 最坏情况:O(n log n)
- 空间复杂度:O(n)
- 排序方式:Out-place
- 稳定性:稳定
-
偏方型
计数排序
- 一种很巧妙的排序算法
- 比较特殊的排序算法,只针对特殊数据的排序
- 将对应的数据让数组的索引对应值+1
- 最后遍历数组,索引对应的值是几就打印几
比如一个中学有2000名同学进行了期末考试,现在要求按照分数对学生进行排序?[0,750]
构建一个长度为751的数组new String[751]
然后学生考了多少分就把分数当成下标,将值拼接到对应的位置
最后从高到低依次取出数组中的值,那么学生的名次就排序完成了,对于成绩相同的放在同一个下标里面
- 平均时间复杂度:O(n + k)
- 最好情况:O(n + k)
- 最坏情况:O(n + k)
- 空间复杂度:O(k)
- 排序方式:Out-place
- 稳定性:稳定
桶排序
- 将数字按照范围进行分割
- 然后对分割后的数据进行排序(继续分割)
- 将来数据分桶要特别注意数据倾斜的问题
就比如银行根据存的金额排序用户,那么这个时候用计数排序就不太合适了,因为存钱的最多可能在上百亿,
桶排序就是先将这个区间分成多个小区间,比如1-10000,10001-20000…,然后再小区间进行排序,因为分桶后,桶外有序,桶内无序
- 平均时间复杂度:O(n + k)
- 最好情况:O(n + k)
- 最坏情况:O(n^2)
- 空间复杂度:O(n + k)
- 排序方式:Out-place
- 稳定性:稳定
基数排序
基数排序是按照低位先排序,然后手机,在按照高位排序,然后再收集,依次类推,直到最高位
比如: 3 44 38 5 47 15 36 26 27 2 46 4 19 50 48
按照个位排序: 0 1 2 3 4 5 6 7 8 9
50 2 3 44 5 36 47 38 19
4 15 26 27 48
46
按照顺序写出: 50 2 3 44 4 5 15 36 26 46 47 27 38 48 19
再按照十位排序:0 1 2 3 4 5 6 7 8 9
2 15 26 36 44 50
3 19 27 38 46
4 47
5 48
按照顺序写出:2 3 4 5 15 19 26 27 36 38 44 46 47 48 50
- 平均时间复杂度:O(n * k)
- 最好情况:O(n * k)
- 最坏情况:O(n*2)
- 空间复杂度:O(n + k)
- 排序方式:Out-place
- 稳定性:稳定