定义
优先队列是利用堆来实现的,堆可以看做是一棵完全二叉树的顺序存储结构。在这棵二叉树中,如果每一个节点的值都大于等于左右孩子的值,则称之为“最大堆”。如果每一个节点的值都小于等于左右孩子的值,则称之为“最小堆”。
应用
在算法设计中,经常用到从序列中找一个最小值(最大值)的操作,例如最短路径,哈夫曼编码等都需要找到一个最小值,如果从序列中顺序查找最值需要 O ( n ) O(n) O(n)
的时间。而从优先队列中查找最值,则需要 O ( l o g n ) O(logn) O(logn)的时间。
优先队列中堆的创建需要 O ( n ) O(n) O(n)的时间(下面讲解原因),而取最值只需要 O ( l o g n ) O(logn) O(logn)的时间。也就是二叉树的高度。
python创建最大堆
# coding=utf-8
class Heap(object):
def __init__(self, nums):
"""
创建最大堆
:param nums:
"""
self.nums = nums
self.length = len(nums)
def _sink(self, k):
"""
节点下沉
:param k:
:return:
"""
while 2 * k < self.length:
j = 2 * k # 指向右孩子
if j < self.length and self.nums[j] < self.nums[j + 1]:
j += 1 # 指向左孩子
if self.nums[k] >= self.nums[j]:
break #满足最大堆
else:
self.nums[k], self.nums[j] = self.nums[j], self.nums[k]
k = j
def create(self):
i = self.length // 2
# 从最后一个分支节点n/2开始下沉调整为堆,直到第一个节点
while i >= 0:
self._sink(i)
i -= 1
if __name__ == '__main__':
nums = [12,16,2,30,28,20,16,6,10,18]
heap = Heap(nums)
heap.create()
print(heap.nums)
创建堆的时间复杂度
这里有一个二叉树的简化图,节点没有填值(聚焦分析)。设节点总数为n,二叉树高度 k = l o g 2 n k=log_2{n} k=log2n。则有1/2的节点需要下沉1次,有1/4的节点需要下降2次…有1/2**k的节点需要下降k次。其中1/2**k<=1。
所有节点下沉总次数为:
T = ∑ k = 1 l o g 2 n ( 1 2 k ∗ k ) ∗ n T = \sum_{k=1}^{log_2^n}{(\frac{1}{2^k}*k)}*n T=∑k=1log2n(2k1∗k)∗n
设 s = ∑ k = 1 l o g 2 n 1 2 k ∗ k = 1 2 ∗ 1 + 1 4 ∗ 2 + . . . + 1 2 k ∗ k s = \sum_{k=1}^{log_2^n}{\frac{1}{2^k}*k}=\frac{1}{2}*1+\frac{1}{4}*2+...+\frac{1}{2^k}*k s=∑k=1log2n2k1∗k=21∗1+41∗2+...+2k1∗k
s 2 = 1 4 ∗ 1 + 1 8 ∗ 2 + . . . + 1 2 k + 1 ∗ k \frac{s}{2} =\frac{1}{4}*1+\frac{1}{8}*2+...+\frac{1}{2^{k+1}}*k 2s=41∗1+81∗2+...+2k+11∗k
s − s 2 = 1 2 + 1 4 + 1 8 + . . . + 1 2 k − 1 2 k + 1 ∗ k s-{\frac{s}{2}} =\frac{1}{2}+\frac{1}{4}+\frac{1}{8}+...+\frac{1}{2^k}-\frac{1}{2^{k+1}}*k s−2s=21+41+81+...+2k1−2k+11∗k
s − s 2 s-{\frac{s}{2}} s−2s的前k项为等比数列求和 a 1 ( 1 − q n ) 1 − q = 1 − ( 1 2 ) n \frac{a_1(1-q^n)}{1-q}=1-(\frac{1}{2})^n 1−qa1(1−qn)=1−(21)n,最后一项趋近0
s 2 \frac{s}{2} 2s趋近1,s趋近2。故时间复杂度T为 O ( n ) O(n) O(n)
有问题可以交流,q我:1678354579