分类
分为大、小根堆。大根堆:父节点≥子节点,小根堆同理。
操作(以大根堆为例)
heapInsert
原理:向堆中插入元素,与其父节点比较如果大于父节点,与父节点交换位置。到新位置后重复此操作。
//i是要插入的下标
func heapInsert(arr []int, i int) {
for arr[i]>arr[(i-1)/2]{
swap(arr,i,(i-1)/2)
i=(i-1)/2
}
}
heapify
原理:将i位置的数和子节点比较,如果子节点大于arr[i],交换位置。交换位置后重复此操作。
func heapify(arr []int,i,heapSize int) {
left:=i*2+1
for left<heapSize{
lastest:=left
if left+1<heapSize&&arr[left+1]>arr[left]{
lastest=left+1
}
if arr[lastest]<=arr[i]{
break
}
swap(arr,i,lastest)
i=lastest
left=i*2+1
}
}
时间复杂度
向堆中插入N个元素
O(N*logN)
证明:
向堆中插入第N个元素时为logN,所以最坏的情况为N*logN。
如果向堆中插入2N个元素,当插入N+1个元素时,时间复杂度为logN,所以最好的时间复杂度为NlogN。插入2N个的时间复杂度和N时候一样,N最好的也是NlogN。
最好最坏的情况下都是N*logN。
将堆调整为最大(小)堆
O(N)
证明:
从堆尾逆向到根节点过程中对每个节点进行heapify:
T(N)=(N/2)*1+(N/4)*2+T(N/8)3+….+1logN→T(N)=O(N)
heapsort
证明类似向堆中插入N个元素的过程。