1.大顶堆/大根堆-排序
python
# 堆排序-大顶堆-升序排列
def bigHeapify(arr: [int], start: int, end: int) -> None:
"""向下调整,堆化,父节点与子节点大的比较并交换"""
root = start
# left child index
child = root*2 + 1
while child <= end:
# 比较左右子节点的大值
if child+1 <= end and arr[child] < arr[child+1]:
child += 1
if arr[root] < arr[child]:
# 子节点更大,交换节点与子节点的值
arr[root], arr[child] = arr[child], arr[root]
# 更新节点到子节点位置,继续下一轮交换
root = child
child = root*2 + 1
else:
break
# 递归法
def bigHeapify_(arr, start, end):
pos = start
child = pos*2 + 1
if child < end:
right = child + 1
if right < end and arr[right] > arr[child]:
child = right
if arr[child] > arr[pos]:
arr[pos], arr[child] = arr[child], arr[pos]
bigHeapify_(arr, pos, end)
def heapSort(arr: [int]) -> [int]:
"""大顶堆排序"""
# 初始化非叶子节点
first = (len(arr) >> 1) - 1
for start in range(first, -1, -1):
# 从下往上,从右至左对每个非叶子节点进行向下调整,循环构成大顶堆
bigHeapify(arr, start, len(arr)-1)
# 交换堆顶尾数据,堆数量--,重新堆化
for end in range(len(arr)-1, 0, -1):
# 交换堆顶堆尾数据, 构造大顶堆
arr[0],arr[end] = arr[end], arr[0]
# 重新调整堆,构造大顶堆
bigHeapify(arr, 0, end-1)
return arr
if __name__ == "__main__":
import random
nums = list(range(20))
random.shuffle(nums)
nums = [19, 1, 11, 4, 12, 8]
orderNums = heapSort(nums)
print(orderNums)
golang
func maxHeapSort(nums []int) []int {
// max heap sort
end := len(nums)-1
// 从最后一个非叶子节点开始堆化
for i:=end>>1;i>=0;i-- {
maxHeapify(nums, i, end)
}
// 依次弹出堆顶元素,然后堆化,相当于依次把最大的放尾部
for i:=end;i>=0;i-- {
nums[0], nums[i] = nums[i], nums[0]
end--
maxHeapify(nums, 0, end)
}
return nums
}
func maxHeapify(nums []int, root, end int) {
// 大顶堆堆化,堆顶值小就一直下沉
for {
// 获取做左孩子
child := root*2 + 1
// 越界跳出
if child > end {
return
}
// 比较左右孩子节点,如果右孩子大则取右孩子与root比较,否则左右孩子左孩子大, child不用++
if child < end && nums[child] <= nums[child+1] {
child++
}
// 如果父节点值大于左右孩子的大值,说明,已经堆化
if nums[root] > nums[child] {
return
}
// 交换父节点与较大的子节点
nums[root], nums[child] = nums[child], nums[root]
// 更新父节点为孩子节点,继续与孙节点比较,不断往下沉
root = child
}
}
2.小顶堆/小根堆-排序
python
# 小顶堆-降序排列
def minHeapify(arr: [int], start: int, end: int):
"""大的节点往下沉,小的往上冒-小顶堆化,父节点与小的子节点比较并交换"""
root = start
child = root*2 + 1
tmpVal = arr[start]
while child <= end:
if child + 1 <= end and arr[child+1] < arr[child]:
child += 1
if arr[child] < tmpVal:
arr[root] = arr[child]
root = child
child = 2*root + 1
else:
arr[root] = tmpVal
break
else:
arr[root] = tmpVal
def minHeapSort(arr: [int], k: int) -> [int]:
"""小顶堆,升序排列, topK"""
# 以arr切片作为heap的初始序列
heap = arr[:k]
# 初始化topK的小顶堆的非叶子节点
first = (k-2) >> 1
# 小顶堆,堆化
for i in range(first, -1, -1):
minHeapify(heap, i, k-1)
# 依次遍历arr的第k+1及以后的元素,入小顶堆顶,小顶堆化
for i in range(k, len(arr)-1):
if arr[i] > heap[0]:
heap[0] = arr[i]
minHeapify(heap, 0, k-1)
# 排序heap, 小顶堆数量--
for i in range(k-1, -1, -1):
heap[0], heap[i] = heap[i], heap[0]
minHeapify(heap, 0, i-1)
return heap
def minHeapSort_(arr: [int]) -> [int]:
"""小顶堆,降序输出"""
length = len(arr)
# 初始化非叶子结点
first = (length-2) >> 1
# 遍历非叶子节点,小堆化
for i in range(first, -1, -1):
minHeapify(arr, i, length-1)
# 排序数组, 小顶堆数量--
for i in range(length-1, -1, -1):
arr[0], arr[i] = arr[i], arr[0]
minHeapify(arr, 0, i-1)
return arr
if __name__ == "__main__":
nums = [0, 8, 9, 12, 13, 15, 21, 23]
# print(minHeapSort(nums, 5)) # top5, 前5的数
# print(minHeapSort(nums, 8)) # k == len(nums), topK即为原数组的降序排列, copy
print(minHeapSort_(nums))
golang
func minHeapify(arr []int, root, end int) {
// 小顶堆,堆化,非叶子节点大的下沉
for {
child := root*2 + 1
// 越界跳出
if child > end {
return
}
// root的值和子节点的小值比较
if child < end && arr[child] >= arr[child+1] {
child++
}
// root节点已经小于子节点,跳出
if arr[root] < arr[child] {
return
}
// root节点大于等于子节点,交换
arr[root], arr[child] = arr[child], arr[root]
root = child
}
}
func minHeapSort(arr []int) []int {
// 小顶堆,降序输出
length := len(arr)
// 非叶子节点初始化, int(n/2)
first := (length-2) >> 1
// 遍历所有非叶子节点,大的下沉
for i:=first;i>=0;i-- {
minHeapify(arr, i, length-1)
}
// 依次弹出堆尾节点,交换后继续堆化
for i:=length-1;i>=0;i-- {
arr[0], arr[i] = arr[i], arr[0]
minHeapify(arr, 0, i-1)
}
return arr
}
func minHeapSort_(arr []int, k int) []int {
// 小顶堆, top K
heap := arr[:k]
// 初始化非叶子节点
first := (k-2) >> 1
// 形成一个数量为k的小顶堆
for i:=first;i>=0;i-- {
minHeapify(heap, i, k-1)
}
// 遍历后续节点,只有大于堆顶的元素,放入堆顶,堆化
for i:=k;i<len(arr)-1;i++ {
if arr[i] > heap[0] {
heap[0] = arr[i]
minHeapify(heap, 0, k-1)
}
}
// 依次弹出heap堆中的堆顶元素,弹出的元素就是topK
for i:=k-1;i>=0;i-- {
heap[0], heap[i] = heap[i], heap[0]
minHeapify(heap, 0, i-1)
}
return heap
}
3.大顶堆功能实现
参考小顶堆的功能实现
4.小顶堆功能实现
实现功能:
- 堆化,从n//2节点开始,和子节点比较,节点小则交换父节点与子节点,然后继续与孙节点比较,一直到叶子节点,总之遇到更小的子节点则下沉
- 堆的插入,先加入到尾部,然后堆化
- 堆的弹出或删除,弹出堆尾节点,保存堆顶节点,交换堆顶堆尾元素,重新堆化,让新堆顶元素下沉,堆化
- 获取堆顶元素
- 获取前k大元素,新建容器heap,获取到原数组的前k个元素切片,堆化heap,从k开始遍历arr,只要比heap[0]大,就令heap[0]等于该值,重新堆化,最后依次倒序弹出堆顶元素,每弹出一个,重新堆化(end--)
python
# -*- coding: utf-8 -*-
基于小顶堆的实现
实现功能:
-1.push(), 堆的插入
-2.pop(), 堆顶弹出/删除
-3.peak(), 获取堆顶元素
-4.kLargest(), 获取k个最大, 降序
-5.heapify(), 建堆
class MinHeap:
def __init__(self, arr=None):
self.heap = arr or []
def _heapify(self, arr):
"""from the last non-leaf node, heapify"""
if len(arr) > 0:
end = len(arr) - 1
first = end >> 1
for i in range(first, -1, -1):
self._siftdown(arr, i, end)
def _siftdown(self, arr: [int], start: int, end: int):
"""cur root sink, compare with sub_node, if cur > sub_node, swap them, repeat, until to the leaf node"""
root = start
child = root*2 + 1
while child <= end:
if child+1 <= end and arr[child] > arr[child+1]:
child += 1
if arr[root] > arr[child]:
arr[root], arr[child] = self._swap(arr[root], arr[child])
root = child
child = root*2 + 1
else:
break
def _swap(self, a, b):
a, b = b, a
return a, b
def heapify(self, arr):
"""transform arr to heap"""
self._heapify(arr)
def push(self, heap, item):
"""insert new item to heap's tail, heapify"""
heap.append(item)
self._heapify(heap)
def pop(self, heap):
"""pop the last item of arr, and heapify itself"""
if len(heap) == 0:
raise Exception("IndexError, heap is empty")
lastItem = heap.pop()
if heap:
peakItem = heap[0]
heap[0] = lastItem
self._heapify(heap)
return peakItem
return lastItem
def peak(self, heap):
"""return peak of heap"""
if len(heap) == 0:
raise Exception("IndexError, heap is empty")
return heap[0]
def kLasrgest(self, arr, k):
"""arr -> heap, use minHeapSort to return k largest items"""
if len(arr) == 0:
return []
if k == 1:
result = max(arr)
return [result]
heap = arr[:k]
self._heapify(heap)
for i in range(k, len(arr)-1):
if arr[i] > heap[0]:
heap[0] = arr[i]
self._siftdown(heap, 0, k-1)
for i in range(k-1, -1, -1):
heap[0], heap[i] = heap[i], heap[0]
self._siftdown(heap, 0, i-1)
return heap
if __name__ == "__main__":
import heapq
import random
nums = list(range(100))
random.shuffle(nums)
randomNums = nums[:10]
print(randomNums)
heap = MinHeap()
# heap.heapify(randomNums)
# heap.push(randomNums, 1200)
# print(randomNums)
print(heap.kLasrgest(randomNums, 5))
参考: