排序算法剖析

前言

学习自用,排序算法再回顾,这里就不放代码了

正文

冒泡排序

冒泡是从前往后相邻比较,每一次比较会把当前最大值传到后面,传到最后面以后就不用管最后面的了

因为他是只比较相邻的而且是从前往后的,所以适合用在链表的排序,(因为单向链表从前往后走,且相邻之间很容易用一个next指针比较)

从前往后这个特性应该代码的局部性也比较好吧?

时间复杂度是O(n^2),看代码可以说是两个循环所以是O(n^2),具体推导​TODO

​可以看出冒泡排序除了相邻比较以外,还会用到很多次相邻的交换

没有用到任何额外的空间,同时也很容易看出来,可以采用动态规划的思想来优化这个冒泡排序吗TODO

冒泡稳定,因为每次往后走如果碰到相同的是不会移动的

优化:当一次内层循环发现没有元素要交换的时候说明已经有序,提前结束外层循环

优化:拆半插入TODO

选择排序

每一轮找出一个最小值,和最左边位置进行交换,并不断调整最左边界

可以看出和冒泡排序一个区别是它不需要每次都交换,而是都遍历一遍来找到一个最值,相比起冒泡省去了每次遍历的很多次交换

但是时间复杂度还是O(n^2),来自于它的比较次数,不过因为省去的这些swap用时会比冒泡排序更优

空间会用到每次的一个变量来存储最值,还是属于O(1)的复杂度

代码也是很简略,两个for循环

以数组实现的不稳定,基于链表的选择排序是稳定的,网上有人说链表的选择排序反而像插入排序,这个没实现过TODO

插入排序

这个代码不是很直观,但是平时打牌我们都是用这个来排序的,一句话概括是把未排序的插到排好序的序列里

它的代码也是不难,内层的while第一眼可能不太好理解,

它也像冒泡排序一样会涉及到相邻移动的情况,最好情况是不用移动,可以增加代码判断从而结束外层循环,最差情况TODO

新来的可以插在旧的右边,所以不打乱原本相对顺序,插入排序也是稳定的

优化:折半插入TODO

​可以看出,插入排序和选择排序一样都是O(n^2)的复杂度,,但是插入排序的比较次数会更少,因为选择排序每遍都要走完未排序数据,所以从这可知道插入排序如果对于基本有序的数组的效率是最高的

插入排序的数据需要比数据多1个位置,用来留空插入,空间复杂度也是O(1)

 

归并排序

要先知道一个外排的概念,即在O(n)的时间复杂度中把两个有序数据合并,而这样需要用到额外的空间,所以整体的归并排序也是O(n)的空间复杂度

另外很容易知道外排是稳定的,所以总体归并排序也是稳定的

归并的代码分为两部分,归和并,利用递归来实现,选取left->right区间,取mid=两者中间,对两个区间left->mid和mid+1->right分别进行递归,在递归后可看成两个区间数组已经有序,就到了并的部分,把两个区间进行外排,最终放回nums

代码要注意左右区间是如何选择,左闭右开是更为常用的方式

归并总体来说是个分治的思想,可以说是分治来完成的,利用归并排序可以解决一道力扣题叫做最大和,就是利用到了这个归并中并的过程

时间复杂度需要复杂的推导,是nlogn的复杂度,详细推导TODO

有自底向上的优化?

快速排序

美名其曰快速排序.有多种实现方法,还有许多种优化方法,那么多内容能单独开一篇文章来讲快速排序,这里略过

堆排序

首先堆的性质是根部是最值,则每次取个最值放在数组最后面,一个位置,不就是一个选择排序的思想吗,所以也是一个不稳定的

堆排序分为两部分,第一部分是建堆,第二部分是每次取最值后的堆调整,每次取最值调整次数是log(当前树高)

 

第一部分的建堆过程是从下往上的,就像是每次从下往上,即从枝往根冒泡的过程,冒泡的过程即每次选一个最值冒泡到最上面,但是这个冒泡的路径长度是树高

第二部分这个操作叫做堆化heapify,这个得深究下才好理解TODO

非比较类排序

O(n)的排序算法,有桶排序,计数排序,基数排序

希尔排序

不是很懂啊

进阶

选择排序和插入排序的对比:

主要有两个开销,一个是比较的开销,一个是数据交换swap的开销

平均情况下插入排序需要n*(n-1)/4次比较,选择排序固定需要n*(n-1)/2次比较,论比较是插入排序更快,

而插入排序需要元素移动,移动次数是?选择排序则需要元素的互相交换swap,单独的一次移动和一次元素交换明显是移动的开销更小,如果没优化的情况下(我也不知道能怎么优化),一次元素的交换可能相当于三次元素的移动吧,

内省排序

通过这个内省排序可以加深对这些算法的理解,这里先TODO

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值