此堆是数据结构中的堆,非我们程序中的堆栈段的堆。堆是一种完全二叉树,即非最后一层其他层全满的树。
分最大堆和最小堆,最小堆,根节点大于孩子节点,左子树右子树也同样如此,是最小堆。
看图
看这红蓝配色,哈哈我是不会说我是巴萨球迷的哈哈哈。
堆得插入十分简单:只需要在尾部插入,然后调整位置,和父节点比较,通过上浮交换操作,保持堆的特性。
删除操作:只能删除根节点,然后孩子节点填充位置,段尾节点,填充空缺。
由于是完全二叉树,可以使用数组来存储,根节点从1开始,2i是其左节点,2i+1是右节点,每次在尾部插入,在头部删除,类似于一个优先级队列。
下标为0的元素,作为缓存位置,之所以从1开始是为了便于计算。
堆代码python实现。
class heapTree:
def __init__(self, size):
self.Vector = [None] * (size + 1)
self.Capacity = size
self.length = 1
def print(self):
if self.length < 2:
print("")
this_layer_cnt=1;
last_cnt=0;
for i in range(1, self.length):
print(self.Vector[i], end=' ')
if (i-last_cnt) % this_layer_cnt == 0:
last_cnt = i
this_layer_cnt *= 2
print("")
print("")
def insert(self, data):
if self.length >= self.Capacity:
print("the tree is full!!!")
return -1
i = self.length
self.Vector[i] = data;
while i >1:
if self.Vector[i//2] > self.Vector[i]:
self.Vector[0] = self.Vector[i//2]
self.Vector[i//2] = self.Vector[i]
self.Vector[i] = self.Vector[0]
i//=2
self.length += 1
#delete top
def delete(self):
if self.length == 1:
pass
elif self.length <= 2:
self.Vector[1] = None
self.length = 1
else:
i = 1
#chosse min(lchild,right,last) to fill it
while i < self.length:
min_tmp=min(self.Vector, 2*i, 2*i+1, self.length-1)
self.Vector[i] = min_tmp[0]
print("---%d,%d", min_tmp)
if min_tmp[1] == self.length-1:
break;
else:
i = min_tmp[1]
self.length-=1
def min(array,i,j,last):
index = last
min_tmp = array[last];
if i < last and array[i] < min_tmp:
min_tmp=array[i]
index=i
if j < last and array[j] < min_tmp:
min_tmp = array[j]
index=j
return (min_tmp,index)
def main():
hpt = heapTree(100)
hpt.insert(3)
hpt.insert(4)
hpt.insert(2)
hpt.insert(1)
hpt.insert(5)
hpt.insert(8)
hpt.print()
hpt.delete()
hpt.print()
if __name__ == "__main__":
main()
删除时选择左右孩子和最末尾的元素中最小的一个替换自己。
用途
1.求100w个数据中的前100.
100大;构建一个大小为100的最小堆,然后每个数入堆,如果小于根,则不如堆,如果大于,则入堆,同时将根弹出。其实堆就是优先级队列。100个数,层级为7。每个数,最大比较6次;算法复杂度O(NlogN)。如果想提高速度,可以采用“分治而治”的思想,将这100W个数分成100份,每份求前100,然后,在求这100组的前100混合,求得前100的数就是最终要求。
2. 堆排序
构建堆,然后从堆中pop出来,既是有顺序的数。
3. 双堆
一个最大堆和一个最小堆。用途求中位数,避免排序。左子树最小堆,右子树最大堆,左 > 根 > 右。维持中位数方法,如果大于根,入左树,小于根,入右树,左右子树节点个数相差大于2则,根节点入小树一侧,多的子树的根顶替根节点。