目录
0.什么是堆
1.最大堆的实现
2.最小堆的实现
3.堆排序
小堆和大堆分为如下图:
堆需要满足的条件:
1. 必须是二叉树,且必须是完全二叉树
2. 各个父节点必须大于或小于左右结点, 其中最顶层的根结点必须是最大或者最小的
堆可以使用list实现,就是按照层序遍历顺序将每个节点上的值存放在数组中。父节点和子节点之间存在如下的关系:
i 从0 开始
parent = (i-1) // 2; left = 2*i + 1 ; right = 2*(i+1)
堆使用数组的形式表示,不需要使用指针
2. 在堆中增加元素
3,删除根节点,并重建堆结构
#最大堆的实现
class MaxHeap():
def __init__(self, maxSize=None):
self.maxSize = maxSize
self.li = [None] * maxSize
self.count = 0
def length(self):
#求数组的长度
return self.count
def show(self):
if self.count <= 0:
print('null')
else:
print(self.li[: self.count])
def add(self, value):
if self.count >= self.maxSize: #判断是否数组越界
raise Exception('full')
self.li[self.count] = value #将新节点增加到最后
self._shift_up(self.count) # 递归构建大堆
self.count += 1
def _shift_up(self, index):
#往大堆中添加元素,并保证根节点是最大的值:
#1.增加新的值到最后一个结点,在add实现; 2.与父节点比较,如果比父节点值大,则交换
if index > 0:
parent = (index - 1) // 2 # 找到根节点
if self.li[index] > self.li[parent]: #交换结点
self.li[index], self.li[parent] = self.li[parent], self.li[index]
self._shift_up(parent) #继续递归从底往上判断
def extract(self):
#弹出最大堆的根节点,即最大值
#1.删除根结点,将最后一个结点作为更结点 ; 2.判断根结点与左右结点的大小,交换左右结点较大的
if not self.count:
raise Exception('null')
value = self.li[0]
self.count -= 1
self.li[0] = self.li[self.count] #将最后一个值变为第一个
self._shift_down(0)
return value
def _shift_down(self, index):
# 1.判断是否有左子节点并左大于根,左大于右;2.判断是否有右子节点,右大于根
left = 2 * index +1
right = 2 * index + 2
largest = index
#判断条件
# 下面2个条件包含了,判断左右结点那个大的情况。如果为3, 4, 5,:
第一个判断条件使得largest=1,再执行第二个条件,则判断其左结点与右结点的大小
if left < self.length() and self.li[left] > self.li[largest]:
largest = left
if right < self.length() and self.li[right] > self.li[largest]:
largest = right
if largest != index: # 将 两者交换
self.li[index], self.li[largest] = self.li[largest], self.li[index]
self._shift_down(largest)
m = MaxHeap(10)
import numpy as np
np.random.seed(123)
num = np.random.randint(100, size =10) #创建随机的10个数
print(m.length())
for i in num:
m.add(i)
m.show()
print(m.length())
for i in range(5):
print(m.extract(), end=' ,')
#构造最小堆
class MinHeap():
def __init__(self, maxSize=None):
self.maxSize = maxSize
self.array = [None] * maxSize
self._count = 0
def length(self):
return self._count
def show(self):
if self._count <= 0:
print('null')
print(self.array[: self._count], end=', ')
def add(self, value):
#增加元素
if self._count >= self.maxSize:
raise Exception('The array is Full')
self.array[self._count] = value
self._shift_up(self._count)
self._count += 1
def _shift_up(self, index):
#比较结点与根节点的大小, 较小的为根结点
if index > 0:
parent = (index - 1) // 2
if self.array[parent] > self.array[index]:
self.array[parent], self.array[index] = self.array[index], self.array[parent]
self._shift_up(parent)
def extract(self):
#获取最小值,并更新数组
if self._count <= 0:
raise Exception('The array is Empty')
value = self.array[0]
self._count -= 1 #更新数组的长度
self.array[0] = self.array[self._count] #将最后一个结点放在前面
self._shift_down(0)
return value
def _shift_down(self, index):
#此时index 是根结点
if index < self._count:
left = 2 * index + 1
right = 2 * index + 2
#判断左右结点是否越界,是否小于根结点,如果是这交换
if left < self._count and right < self._count and self.array[left] < self.array[index] and self.array[left] < self.array[right]:
self.array[index], self.array[left] = self.array[left], self.array[index] #交换得到较小的值
self._shift_down(left)
elif left < self._count and right < self._count and self.array[right] < self.array[left] and self.array[right] < self.array[index]:
self.array[right], self.array[index] = self.array[index], self.array[right]
self._shift_down(right)
#特殊情况: 如果只有做叶子结点
if left < self._count and right > self._count and self.array[left] < self.array[index]:
self.array[left], self.array[index] = self.array[index], self.array[left]
self._shift_down(left)
mi = MinHeap(10)
print()
print('-------小顶堆----------')
for i in num:
mi.add(i)
mi.show()
print(mi.length())
for _ in range(len(num)):
print(mi.extract(), end=', ')
print()
print(mi.length())
参考:https://blog.csdn.net/qq_23869697/article/details/82735088
https://python-data-structures-and-algorithms.readthedocs.io/zh/latest/15_%E5%A0%86%E4%B8%8E%E5%A0%86%E6%8E%92%E5%BA%8F/heap_and_heapsort/#_4
def maxHeapfy(alist, length, parent):
left = 2 * parent + 1
right = 2 * parent + 2
largest = parent
if left < length and alist[left] > alist[largest]:
largest = left
if right < length and alist[right] > alist[largest]:
largest = right
if largest != parent:
alist[largest], alist[parent] = alist[parent], alist[largest]
maxHeapfy(alist, length, largest) # 递归构建
def buildMaxHeap(alist): # 构建最大堆
n = len(alist)
lastParent = (n-1) // 2
for i in range(lastParent, -1, -1):
maxHeapfy(alist, n, i)
def heapSort(alist):
buildMaxHeap(alist)
n = len(alist)
for i in range(n-1, -1, -1):
alist[0], alist[i] = alist[i], alist[0] # 将最大值放在最后面
maxHeapfy(alist, i, 0)
return alist
a = [30,50,57,77,62,78,94,80,84]
print(a)
print(heapSort(a))
alist = [2, 4, 1, 2, 5, 58, 45, 24, 67]
print(heapSort(alist))
b = [random.randint(1,1000) for i in range(1000)]
print(b)
print(heapSort(b))