数据结构 | 利用二叉堆实现优先级队列

目录

一、二叉堆的操作

二、二叉堆的实现

[2.1 结构属性](#2.1 结构属性)

[2.2 堆的有序性](#2.2 堆的有序性)

[2.3 堆操作](#2.3 堆操作)


队列有一个重要的变体,叫作优先级队列。和队列一样,优先级队列从头部移除元素,不过元素的逻辑顺序是由优先级决定的。优先级最高的元素在最前,优先级最低的元素在最后。因此,当一个元素入队时,它可能直接被移到优先级队列的头部。

实现优先级队列的经典方法是使用叫作二叉堆 的数据结构。二叉堆的入队操作和出队操作均可达到

二叉堆有两个常见的变体:最小堆 (最小的元素一直在队首)与最大堆(最大的元素一直在队首)。

本篇文章实现的是最小堆

一、二叉堆的操作

我们将实现以下基本的二叉堆方法。

  • BinaryHeap()新建一个空的二叉堆。
  • insert(k)往堆中加入一个新元素。
  • findMin()返回最小的元素,元素留在堆中。
  • delMin()返回最小的元素,并将该元素从堆中移除。
  • isEmpty()在堆为空时返回True,否则返回False。
  • size()返回堆中元素的个数。
  • buildHeap(list)根据一个列表创建堆。
python 复制代码
>>> from pythonds.trees import BinaryHeap
>>> bh=BinaryHeap()
>>> bh.insert(5)
>>> bh.insert(7)
>>> bh.insert(3)
>>> bh.insert(11)
>>> print(bh.delMin())
3
>>> print(bh.delMin())
5
>>> print(bh.delMin())
7
>>> print(bh.delMin())
11

二、二叉堆的实现

2.1 结构属性

为了使二叉树能够高效地工作,我们利用树的对数性质来表示它。为了保证对数性能,必须维持树的平衡。平衡的二叉树是指,其根节点的左右子树含有数量大致相等的节点。在实现二叉堆时,我们通过创建一颗完全二叉树来维持树的平衡。在完全二叉树中,除了最底层,其他每一层的节点都是满的。在最底层,我们从左往右填充节点。

完全二叉树的另一个有趣之处在于,可以用一个列表来表示它,而不需要采用"列表之列表"或"节点与引用"表示法。由于树是完全的,因此,因此对于在列表中处于位置p的节点来说,它的左子节点正好处于位置2p;同理,右子节点处于位置2p+1。若要找到树中任意节点的父节点,只需使用python的整数除法即可。给定列表中位置n处的节点,其父节点的位置就是n/2。

2.2 堆的有序性

我们用来存储堆元素的方法依赖于堆的有序性。堆的有序性是指:对于堆中任意元素x及其父元素p,p都不大于x。

2.3 堆操作

新建二叉堆:

python 复制代码
def __init__(self):
    self.heapList=[0]
    self.currentSize=0

接下来实现insert方法。将元素加入列表的最简单、最高效的方法就是将元素追加到列表的末尾。追加操作的优点在于,它能保证完全数的性质,但缺点是很可能会破坏堆的结构性质。不过可以写一个方法,通过比较新元素与其父元素来重新获得堆的结构性质。如果新元素小于其父元素,就将二者交换。

perUp方法:

python 复制代码
def perUp(self,i):
    while i//2>0:
        if self.heapList[i]<self.heapList[i//2]:
            tmp=self.heapList[i//2]
            self.heapList[i//2]=self.heapList[i]
            self.heapList[i]=tmp
        i=i//2

向二叉堆中新加元素:

python 复制代码
def insert(self,k):
    self.heapList.append(k)
    self.currentSize=self.currentSize+1
    self.perUp(self.currentSize)

正确定义insert方法后,就可以编写delMin方法。既然堆的结构性质要求根节点是树的最小元素,那么查找最小值就很简单。delMin方法的难点在于,如果在移除根节点之后重获堆的结构性质和有序性。可以分两步重建堆。第一步,取出列表中的最后一个元素,将其移到根节点的位置。移动最后一个元素保证了堆的结构性质,但可能破坏二叉堆的有序性。第二步,将新的根节点沿着树推到正确的位置,以重获堆的有序性。

perDown方法和minChild方法:

python 复制代码
def percDown(self,i):
    while (i*2)<=self.currentSize:
        mc=self.minChild(i)
        if self.heapList[i]>self.heapList[mc]:
            tmp=self.heapList[i]
            self.heapList[i]=self.heapList[mc]
            self.heapList[mc]=tmp
        i=mc

def minChild(self,i):
    if i*2+1>self.currentSize:
        return i*2
    else:
        if self.heapList[i*2]<self.heapList[i*2+1]:
            return i*2
        else:
            return i*2+1

从二叉堆中删除最小的元素:

python 复制代码
def delMin(self):
    retval=self.heapList[1]
    self.heapList[1]=self.heapList[self.currentSize]
    self.currentSize=self.currentSize-1
    self.heapList.pop()
    self.percDown(1)
    return retval

根据元素列表构建堆:

python 复制代码
def bulidHeap(self,alist):
    i=len(alist)//2
    self.currentSize=len(alist)
    self.heapList=[0]+alist[:]
    while (i>0):
        self.percDown(i)
        i=i-1
相关推荐
EQUINOX112 小时前
【论文阅读】| MoCo精读
论文阅读·人工智能·python·深度学习·机器学习
额鹅恶饿呃12 小时前
C语言中的数据结构和变量
c语言·数据结构·算法
用户83562907805112 小时前
使用 Python 自动化 Excel 公式和函数:完整指南
后端·python
敲代码的嘎仔13 小时前
实习日志day6--实习日志day6--title命名规范化&businessType纠正&补充缺失的@Log注解&报警与通信模块补充&产出阶段总结文档
java·开发语言·人工智能·git·python·实习·大二
江华森13 小时前
Python 实现高德地图找房(一):环境搭建与数据爬虫
开发语言·爬虫·python
VIP_CQCRE13 小时前
用 Ace Data Cloud 快速接入 OpenAI Chat Completions:对话、流式、多轮和多模态一篇打通
python·ai·openai·api·教程
AOwhisky13 小时前
Python 学习笔记(第三期)——流程控制:条件判断与循环结构
运维·笔记·python·学习·云原生·流程控制·循环
万法若空14 小时前
【数据结构-哈希表】哈希表原理
数据结构·算法·散列表
老迟到的茉莉14 小时前
Hermes 是谁?跟 Claude Code 差在哪
开发语言·python
tachibana214 小时前
hot100 翻转二叉树(226)
java·数据结构·算法·leetcode