堆排序与优先级队列

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]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值