插入排序(将一个数据插入有序区间)
从头选一个数据,跟后面进行比较,往后走
例如:摸扑克牌
升序:
最坏:O(N²) 逆序
最好:O(N) 顺序有序
希尔排序(也是一种插入排序)
1.预排序 -- 目标:数组接近有序 分组插排
时间复杂度:O(N*logN)的量级,但是不是
接近N的1.3次方
gap越大,跳的越快,越不接近有序
gap越小,跳的越慢,越接近有序
间隔为gap分为一组(gap取1就是插入排序)
对每组数据插入排序
看成,红色一组,蓝色一组,绿色一组
第一组插入排序完
5 1 2 5 7 4 8 6 3 9
第二组
5 1 2 5 6 4 8 7 3 9
第三组
5 1 2 5 6 3 8 7 4 9
比直接插入排序效率高
例如:9直接会跳9次,这里只需要 < a[end])
堆排序(也是一种)选择排序
时间:O(N*logN)
冒泡排序(是一种交换排序)
时间:O(N²)
最好:O(N)
快速排序(也是一种交换排序)
(前序遍历)
选出一个关键值/基准值 key,把他放到正确的位置(最终排好序要蹲的位置),比6小的放左边,比6大的放右边
时间:O(N*logN)
稳定性:不稳定
1.霍尔法
左边做key,右边先走
右边做key,左边先走好
可以让相遇位置一定比key小,或者就是key
左边找大,右边找小,找到交换
再找再换,直到相遇,和key的位置交换
然后通过递归将左边和右边都排成有序
数据顺序,逆序会导致堆栈过多
可以通过随机找key
或者三数取中(顺序下优于随机找key)
2.挖坑法
把key的数据存起来,把key的位置当做坑位
右边走找到比key大就放到坑位,自己变成新坑位
左边再去找小放到坑位,自己变成新坑
左右先走都可以
相遇一定在坑里面,把key的数据放到坑里
3.前后指针版本
prev,cur
cur找小,如果找到比key小的,++prev,cur和prev位置的值交换,++cur
cur找的比key大的值,++cur
说明:
1.prev要么紧跟着cur(prev下一个就是cur)
2.prev跟cur中间间隔着比key大的一段区间
在剩余区间小于一定范围时,可以换成直接插入法,不然剩5个数都要递归7次
把最后一层变成直接插入,就可以把递归的消耗减小到一半
4.非递归
1.在栈里面取一段区间,单趟排序
2.单趟分割的子区间入栈
3.如果子区间只有一个值或者不存在就不需要入栈
深度遍历
面对大量重复数据的时候要不会栈溢出,要不会效率下降的非常厉害
可以用三路划分法
归并排序(后序遍历)
两个有序区间归并:依次比较,小的尾插到新空间
平均情况 最好情况 最坏情况 辅助空间 稳定性
冒泡排序 O(N²) O(N) O(N²) O(1) 稳定
选择排序 O(N²) O(N²) O(N²) O(1)
不稳定(可能感人干扰其他)
直接插入 O(N²) O(N) O(N²) O(1) 稳定
希尔排序
O(NlogN~N²)
O(N^1.3)
O(N²)
O(1)
不稳定(相同的数据可能分到不同的组预排序)
堆排序
O(NlogN)
O(NlogN)
O(NlogN)
O(1)
不稳定(相同的数可能在不同的深度)
归并排序
O(NlogN)
O(NlogN)
O(NlogN)
O(N)
稳定
选择排序
O(NlogN)
O(NlogN)
O(N²)
O(logN)-O(N)
不稳定(key的位置不一定在哪)