前言
好久没写博客了,这篇内容还是很久之前就写好的,现在想想还是把它贴出来吧,也算是贡献一点代码。
另外想直接获取代码的直接拷贝即可,分析过程写的不是很有逻辑性,大家将就着看吧。
分析过程
最小堆和最大堆结构图如下:
堆需要满足的条件:
-
必须是二叉树,且必须是完全二叉树
-
各个父节点必须大于或小于左右结点, 其中最顶层的根结点必须是最大或者最小的
实现这样的堆可以采用list或者数组来实现,将这样的二叉树以层序遍历存储在数组中,对于这个list或者数组中的第K个节点其:
- 父节点的下标为:parent = (k-1)/2
- 左子节点下标为: left = k*2 + 1
- 右子节点下标为: right = k*2 + 2
其对应的关系如下图:
在堆中添加一个元素,将新加入的元素放到队尾,然后改变树的结构:
弹出根元素,把最后一个元素移到根节点,然后改变树的结构:
代码实现
class minheap:
def __init__(self, item=[]):
# 初始化。item为数组 可以存放结构体 只不过后面进行数值比较时需要加上相应的引用
self.items = item
self.len = len(self.items)
def min_heap(self, k):
#最小堆化 使得以k为根节点的子树变成最小堆 前提是其下面的所有子树都已经是最小堆了
left = k*2+1
right = k*2+2 #获取k的左右子节点 数组按照层序遍历存储 其左右子节点的计算方式就是这样
mink = k
if left < self.len and self.items[left]<self.items[mink]:#如果左子节点存在 并且比父节点小 则应该交换一下 先记录下来
mink = left
if right < self.len and self.items[right]<self.items[mink]:
mink = right
if mink != k:#如果找到了比父节点还小的值 那就把最小值和其进行交换
self.items[k],self.items[mink] = self.items[mink],self.items[k]
self.min_heap(mink)#然后把第mink节点改变了 所以得把以这个节点为父节点的子树递归成最小堆
# 如果当前节点都小于其左右子节点 则无需进行交换
def build_min_heap(self):
#创建初始化的最小堆 从最下面一层的最右边的一个子节点的父节点进行遍历
last_node = self.len-1
last_pa = int((last_node-1)/2 )#第k个节点的父节点计算方式
while last_pa >= 0:
self.min_heap(last_pa)
last_pa -=1
def get_min(self):#获取当前最小的值 不会对其有影响
if len(self.items)>0:
return self.items[0]
else:
return None
def pop(self):#弹出栈顶 最小值 然后把最后一个节点移动到栈顶 再对其进行最小堆化
if len(self.items)>0:
val = self.items[0]
self.items[0] = self.items[-1]
self.items.pop()
self.len = len(self.items)
self.min_heap(0)
return val
else:
None
def add(self,k):#向堆里添加新的元素
self.items.append(k)#将新元素加入到栈尾 然后重新对整个进行最小堆化
self.len = len(self.items)
last = self.len -1
last_pa = int((last-1)/2 )#第k个节点的父节点计算方式
while last_pa >= 0:
if self.items[last_pa]<=self.items[last]:#如果最后一个节点的父节点的值已经满足条件 则无需调整树的结构
break
else :#否则需要将两个节点的值互换 然后向上
self.items[last_pa],self.items[last] = self.items[last],self.items[last_pa]
last = last_pa
#此时以last为父节点的子树一定满足最小堆的条件了 但是其父节点不一定满足条件 因此需要向上判断
last_pa = int((last-1)/2 )
a = []
k = minheap(a)
k.build_min_heap()
print(k.items)
print(k.pop())
print(k.items)
k.add(1)
print(k.items)
k.add(10)
print(k.items)
Notes:
博客中的图都是直接拷贝的另一博客的,当时忘了记下链接了,如有侵权,请通知删除。