1. 堆排序
1.1 堆性质
堆是具有以下性质的完全二叉树:
1. 每个节点的值都>=其左右孩子的值(大顶堆);
2. 每个节点的值都<=其左右孩子的值(小顶堆);
1.2 堆排序定义
利用堆这种数据结构而设计的排序算法,是一种选择排序。
稳定,时间复杂度:最好=平均=最坏=o(nlogn)
空间复杂度:o(1)
基本思想:将待排序列构造成一个大顶堆,此时整个序列的最大值就是堆顶的根结点。将其与末尾元素进行交换,此时末尾元素就为最大值,然后将剩余n-1个元素重新构造成一个堆,如此反复便能得到一个有序序列了。
1.3 堆排序实现
def head_sort(arr):
if not arr or len(arr) < 2:
return arr
n = len(arr)
# 1. 构建大顶堆(初始堆)
for i in range(n//2-1, -1, -1):
# 从最后一个非叶子节点,自上而下,自右至左调整堆
adjust_heap(arr, n, i)
# 2. 调整堆结构,并交换堆顶与末尾元素(从最后一个元素到第2个元素(n-1 --> 1))
for i in range(n-1, 0, -1): # 从无序区的最后一个节点起开始调整
arr[i], arr[0] = arr[0], arr[i] # 交换
adjust_heap(a, i, 0) # 调整
调整堆:将当前无序区的堆顶元素a[0]与该区间最后一个记录交换,得到新的无序区a[0,1,...,n-2]和新的有序区a[n-1],有序区范围从后往前不断扩大,直到n个。
# 调整堆,使用沉降法实现大根堆(heapify堆化)
def adjust_heap(a, heap_size, i):
left = 2 * i + 1
right = 2 * i + 2
max = i
if left < heap_size and a[left] > a[max]:
max = left
if right < heap_size and a[right] > a[max]:
max = right
if max != i:
a[i], a[max] = a[max], a[i]
adjust_heap(a, heap_size, max)
1.4 测试
a = [4, 3, 9, -1, 7, 3]
phead_sort(a)
print(a)
# [-1, 3, 3, 4, 7, 9]
2. 优先队列
这里实现一个大顶堆,包括peek()、add()、remove()等方法。
性质:
优先级队列无论增加或删除元素,都要维护队列内现有元素构成一个大顶堆。
2.1 打印队列元素
class PriorQueue(object):
def __init__(self, elist=[]):
self.elist = elist
# 打印队列元素
def print_queue(self):
print(self.elist)
2.2 获得具有最大关键字的元素
def peek(self):
return self.elist[0] if self.elist else -1
2.3 增加一个节点
先将该节点插入到队尾,并与它的父节点比较,若大于则交换,再与新的父节点比较(自下而上调整堆),直到根节点。
def add(self, e):
self.elist.append(e)
i = len(self.elist) - 1
parent = (i-1)//2 if i > 0 else -1
while parent >= 0 and self.elist[parent] < self.elist[i]:
self.elist[parent], self.elist[i] = self.elist[i], self.elist[parent]
i = parent
parent = (i-1)//2 if i > 0 else -1
2.4 删除一个节点
根结点出队列,并将队尾元素移动到根节点处(自上而下与左右孩子比较,调整堆)。
def remove(self):
if not self.elist:
return -1
if len(self.elist) == 1:
return self.elist.pop()
e = self.elist[0]
self.elist[0] = self.elist.pop()
max, i = 0, 0
n = len(self.elist)
while i < n:
left, right = 2*i+1, 2*i+2
if left < n and self.elist[left] > self.elist[max]:
max = left
if right < n and self.elist[right] > self.elist[max]:
max = right
if max != i:
self.elist[max], self.elist[i] = self.elist[i], self.elist[max]
i = max
else:
break
return e
2.5 测试
a = [9, 6, 8, 3, 5, 2]
queue = PriorQueue(a)
# queue.add(1)
queue.remove()
print(queue.print_queue())
# [8, 6, 2, 3, 5]