回忆一下堆排序:
思路:
sift函数:调整,将父亲和孩子(左孩子和右孩子中最大的那个数) 然后和父亲比较,如果孩子大就将孩子的位子变为下一个父亲,往下拉 并且将孩子的值赋给他的父亲;j<=high 条件认可:
防止父亲在最后一层,魔法般的对应父亲大于孩子的情况,如果父亲大于孩子就将父亲的值写到父亲的位置上去,这和父亲落到最后位置的情况处理方式一样,十分巧妙。
建堆:农村包围城市,从最后一个堆开始调整 直到整个堆,调整为一个大根堆或是一个小根堆。
挨个出数:从最后一个数开始,循环处理,与第一个数(堆顶这个数是最大或者最小的数)交换,再次调成大根堆或者小根堆,注意第一次调整是high的值应该指向n-2的位置。利用循环,每次出来交换数,调整,直到将列表有序化。
言归正传:
堆排序应用之Topk问题:
现在有n个无序的数,设计算法得到前k个大的数(k<n)
例如:微博热门评论排行,网站排名......
解决思路: # k为常数
- 排序后切片 O(nlogk)
- 排序lowbi三人组(冒泡,选择,插入) O(kn)
- 堆排序思路 O(nlogk)
所以我们在这里需要使用堆排序的降序调整:
如何修改升序?就改两个地方,如图:
Topk函数实现:
总结:
切片前k个数;
遍历k个数后面的数,选出大于堆顶的数据+每次都调整让对应堆顶始终是最小的数。
挨个出这k个数,与堆排序一样 注意:这里处理的列表是包含这k个数的并不是原列表!
有想法的小伙伴可以在留言区下,说说你的思路,包括上面提及到的lowbi三人组,切片排序/..
归并排序
设计到递归,与快数排序一样,不是很好理解,但是好写一点。
原理:
n个数先拆到最后每个数都是单个数,递归到最大限度(low<high) 开始使用归并merge()
一层一层排序,直到最后一层排序就结束, 如图:
核心merge函数实现:
真正的归并排序实现:
空间复杂度:
空间复杂度是:O(n)因为开辟了一个new_list列表来存储数据,所以就这样了。。
时间复杂度:
按照层数对应 每次归并排序(一次归并排序的时间复杂度是O(n))
所以,归并排序整体的时间复杂度是O(nlogn)
排序总结:
快速归并堆排序的执行时间比较:
什么叫稳定性:
简单而言,就是说排序时,数是一个一个比较的,而不是一片一片扫描。
可以看出:冒泡、插入、归并排序稳定!
显然,快速排序最快,但是也有最坏的情况,我们可以生成随机下标与第一个数进行交换,降低这种最坏的风险,降低这种概率。
综上所述,这就是本篇文章的所有内容,谢谢大家的观看,感谢!!!