博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
二叉堆
阅读量:4560 次
发布时间:2019-06-08

本文共 3999 字,大约阅读时间需要 13 分钟。

二叉堆

1 基于二叉堆的优先队列

在优先级队列中,队列中的项的逻辑顺序由它们的优先级确定。最高优先级项在队列的前面,最低优先级的项在后面。因此,当你将项排入优先级队列时,新项可能会一直移动到前面。

我们只使用一个单一的列表作为二叉堆的内部表示。

二叉堆有两个常见的变体:最小堆(其中最小的键总是在前面)和最大堆(其中最大的键值总是在前面)。

我们将实现最小堆。

2 二叉堆实现

利用二叉树的对数性质来表示我们的堆。

2.1 完整二叉树

一个完整的二叉树是一个树,其中每个层都有其所有的节点,除了树的最底层,从左到右填充。

2.2 堆的属性

可以使用单个列表来表示它。

父节点的左子节点(在位置 p 处) 是在列表中位置 2p 中找到的节点。 类似地,父节点的右子节点在列表中的位置 2p + 1。为了找到树中任意节点的父节点,我们可以简单地使用 Python 的整数除法。

1539144165586

堆的排序属性如下:在堆中,对于具有父 p 的每个节点 x,p 中的键小于或等于 x 中的键。

2.3 堆操作

2.3.1 init 函数

一个空的二叉堆有一个单一的零作为 heapList 的第一个元素,这个零只是放那里,用于以后简单的整数除法。

def __init__(self):    self.heapList = [0]    self.currentSize = 0

2.3.2 insert 函数

将项添加到列表中最简单,最有效的方法是将项附加到列表的末尾。 它维护完整的树属性。但可能违反堆结构属性。可以编写一个方法,通过比较新添加的项与其父项,我们可以重新获得堆结构属性。 如果新添加的项小于其父项,则我们可以将项与其父项交换。

下图展示了将新添加的项替换到其在树中的适当位置所需的操作。

1539144683528

当添加完一个新项后,需要对二叉堆进行维护,由 perUp 函数接管,它在树中向上遍历一个新项并正确定位该新项。

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
def insert(self, k):    self.heapList.append(k)    self.currentSize += 1    self.perUp(self.currentSize)

2.3.3 delMin 函数

堆属性要求树的根是树中的最小项,所以找到最小项很容易。

难点在根被删除后恢复堆结构和堆顺序属性。

  1. 通过获取列表中的最后一个项并将其移动到根位置来恢复根项。
  2. 通过将新的根节点沿着树向下推到其正确位置来恢复堆顺序属性。

1539247149051

为了维护堆顺序属性,我们所需要做的是将根节点和最小的子节点交换。

将节点和其子节点重复交换,直到节点被交换到正确的位置,使它小于两个子节点。

percDown 和 minChild 方法实现树交换节点。percDown 方法确保最大的子节点总是沿着树向下移动。

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 + 1def perDown(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

delMin 函数的代码。

def delMin(self):    retval = self.heapList[1]    self.heapList[1] = self.heapList[self.currentSize]    self.currentSize = self.currentSize - 1    self.heapList.pop()    self.perDown(1)    return retval

2.3.4 buildHeap 函数

buildHeap 函数用于构建整个堆。

1539247490777

def buildHeap(self, alist):    i = len(alist) // 2    self.currentSize = len(alist)    self.heapList = [0] + alist[:]    while i > 0:        self.perDown(i)        i = i - 1

2.4 完整代码

class BinHeap(object):    def __init__(self):        self.heapList = [0]        self.currentSize = 0    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    def insert(self, k):        self.heapList.append(k)        self.currentSize += 1        self.perUp(self.currentSize)    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    def perDown(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 delMin(self):        retval = self.heapList[1]        self.heapList[1] = self.heapList[self.currentSize]        self.currentSize = self.currentSize - 1        self.heapList.pop()        self.perDown(1)        return retval    def buildHeap(self, alist):        i = len(alist) // 2        self.currentSize = len(alist)        self.heapList = [0] + alist[:]        while i > 0:            self.perDown(i)            i = i - 1if __name__ == '__main__':    bh = BinHeap()    bh.buildHeap([9, 5, 6, 2, 3])    print(bh.delMin())    print(bh.delMin())    print(bh.delMin())    print(bh.delMin())    print(bh.delMin())

701977-20190501094902261-873549745.png

转载于:https://www.cnblogs.com/banshaohuan/p/9773430.html

你可能感兴趣的文章
进程/线程切换原则
查看>>
正则表达式语法
查看>>
20165301 2017-2018-2 《Java程序设计》第四周学习总结
查看>>
Vue的简单入门
查看>>
urllib 中的异常处理
查看>>
通过SQL Server的扩展事件来跟踪SQL语句在运行时,时间都消耗到哪儿了?
查看>>
WIFI密码破解全攻略
查看>>
gulp
查看>>
pgsql查询优化之模糊查询
查看>>
不变模式
查看>>
matlab去云雾
查看>>
500lines项目简介
查看>>
Asp.net core logging 日志
查看>>
BOM浏览器对象模型
查看>>
Jq 遍历each()方法
查看>>
Android源码分析:Telephony部分–phone进程
查看>>
20181227 新的目标
查看>>
HDFS写流程
查看>>
使用命令wsimport构建WebService客户端[转]
查看>>
第八遍:链接详解
查看>>