zoukankan      html  css  js  c++  java
  • 二叉堆

    二叉堆

    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 + 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
    

    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 - 1
    
    
    if __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())
    

  • 相关阅读:
    Visual Studio 2010的活动,有兴趣的朋友可以来参加
    .NET 业务框架开发实战之九 Mapping属性原理和验证规则的实现策略
    Javascript 返回上一页
    Entity Framework 4.0新增对TSQL的支持
    .Net 4.0中支持的更加完善了协变和逆变
    c#4.0——泛型委托的协变、逆变
    JQuery 常用方法基础教程
    AspNetPager分页示例
    微软一站式示例代码浏览器
    UI与实体的映射
  • 原文地址:https://www.cnblogs.com/banshaohuan/p/9773430.html
Copyright © 2011-2022 走看看