堆是一颗特殊的二叉树,一般分为最小值堆和最大值堆,最小值堆满足如下的特点:二叉树中的任一节点的关键码值都小于或者等于它的两个子女节点的关键码值。最大值堆则反之。
堆的典型应用场景有:
-
堆排序:每次把堆的顶点元素放在二叉树的尾部,之后重新建堆。
-
在求最优解的算法中应用。例如求最短路径的Dijkstra算法中,使用堆进行优化等。
# encoding=utf-8
#左叶子、右叶子和父节点,三个元素,找到最大的一个
def maxHeap(heap,heapSize,i):
#i为某个节点
#它的左节点坐标:2i
#那么它的右节点坐标:2i + 1
#它的父节点:i/2
left = 2*i +1
right = 2*i +2
larger = i
#通过2次if的比较,将left、right和lager三者的最大值找到
# maxHeap 这个函数的交换逻辑,应该是既不算上滤,也不算下滤
#上滤:新插入元素和父节点比对,发生交换。下滤:左右节点比对后发生交换
#maxHeap 这个函数的交换逻辑是三个数找到最大的,和上滤下滤还是有一些区别。
if left < heapSize and heap[larger] < heap[left]:
larger = left
if right < heapSize and heap[larger] < heap[right]:
larger = right
#如果lager的值不是i,说明i的值需要和最大值进行交换
#因为i的坐标是最大堆的堆顶,所以必须是最大值
#如果不是i最大,则说明左结点,或者右节点最大,交换值
#后,说明下面的堆有可能需要进行调整,所以通过递归来
#建立左(右)结点下的最大堆。
#如果最大值就是i,没有进行交换值,所以不需要进行建立
#左(右)结点下的最大堆,这是因为
if larger != i:
heap[i],heap[larger] = heap[larger],heap[i]
maxHeap(heap,heapSize,larger)
#以上步骤完成,堆顶坐标为i坐标的最大子堆建立好了
def buildMaxHeap(heap):
heapSize = len(heap)
#堆的长度//2可以找到堆里面的
#最后一个带有子节点的节点
#循环可以实现从堆的最下层节点开始建堆
#每次建立的堆都是一个最大堆
#简单来说把所有字段都建成最大堆
#然后组成了最终的最大堆
for i in range((heapSize-1)//2,-1,-1):
maxHeap(heap,heapSize,i)
#这个循环要理解一下:这个循环调用,表示从最下层的子树,开始实现最大堆,这个就是从最下层开始建立最大堆的过程
def heapSort(heap):
#先把所有元素先建立一个最大堆
buildMaxHeap(heap)
#将堆中所有的元素都遍历一遍
#让每个元素都做一次堆顶
#然后将堆顶的每个元素都换到堆的最后一个节点
for i in range(len(heap)-1,-1,-1):
heap[0],heap[i] = heap[i],heap[0]
#maxheap中的i是列表的长度,这样可以防止追加到
#堆后面的元素重新被当做最大堆元素进行建队
maxHeap(heap,i,0)
return heap
if __name__ == '__main__':
heap1 = [3,4,5,6,23,4,1,1,23,45,6678]
print (heap1)
heapSort(heap1)
print (heap1)
时间复杂度:
O(N*logN)。