归并排序
先排序左边,再排序右边,最后通过一个辅助数组merge
利用master公式估计时间复杂度:
T(N) = 2*T(N/2) + O(N)
a = 2, b=2, d=1
时间复杂度为:O(N*logN),额外空间复杂度:O(N)
拓展:
-
小和问题
数组中求每个数左边比他小的数的和。
普通解法:O(N^2)
归并解法:在merge和sort的过程中发现左侧数比右侧数小就把 “小和” 加上 -
逆序对问题
左边的数比右边的数小
堆(优先级队列)
数组实现的完全二叉树(从左到右依次变满)结构
节点个数是N, 高度是logN.
i 位置的左孩子是2i+1, 右孩子是2i+2, 父节点是 (i-1)/2
根节点为0
- 方法
- add (member)
新加入的数据放到最后位置,并依次和父节点比较大小, 若比父节点大则交换两者位置. - intgetmax()
输出最大值,并更新最大堆
返回最大值后, 把最后一个数放到根节点, 然后和最大子节点比较大小并调整. heapify() - 扩容
一次扩大一倍
堆排序
-
先满足0~0范围是堆,然后依次添加数字,逐渐建立堆O(N*logN)
如果一次性得到全部数据, 从下往上逐渐保证每个子树调整成大根堆的时间复杂度更低 O(N).
-
每次把根节点和最后一个节点交换, 并将heapsize减1
-
将新的根节点向下heapify到目标位置
-
重复2,3过程,直到heapsize等于0
时间复杂度: O(N*logN)
例题:
一个几乎有序的数组, (每个元素移动距离不超过k, k比较小) 选择最佳排序方法.
利用一个大小为k的最小堆, 每次弹出最小的放到0位置(1,2,3…), 再把后一个(k+1)数放进堆里, 周而复始.
O(N*logk) -> O(N)
python中的堆
默认为小根堆, 若需要大根堆, 保存成相反数 (加负号)
import heapq
heap = []#建立一个常见的堆
heappush(heap,item)#往堆中插入一条新的值
item = heappop(heap)#弹出最小的值
item = heap[0]#查看堆中最小的值,不弹出
heapify(x)#以线性时间将一个列表转为堆
item = heapreplace(heap,item)#弹出一个最小的值,然后将item插入到堆当中。堆的整体的结构不会发生改变。
heappoppush()#弹出最小的值,并且将新的值插入其中
merge()#将多个堆进行合并
nlargest(n , iterbale, key=None)从堆中找出做大的N个数,key的作用和sorted( )方法里面的key类似,用列表元素的某个属性和函数作为关键字