当前位置:Gxlcms > Python > python中二叉堆的详细介绍(代码示例)

python中二叉堆的详细介绍(代码示例)

时间:2021-07-01 10:21:17 帮助过:55人阅读

本篇文章给大家带来的内容是关于python中二叉堆的详细介绍(代码示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。

一、堆

数据结构 堆(heap) 是一种优先队列。队列是一种先进先出的数据结构。队列的一个重要变种称为优先级队列。使用优先队列能够以任意顺序增加对象,并且能在任意的时间(可能在增加对象的同时)找到(也可能移除)最小的元素,也就是说它比python的min方法更加有效率。
在优先级队列中,队列中的项的逻辑顺序由它们的优先级确定。最高优先级项在队列的前面,最低优先级的项在后面。因此,当你将项排入优先级队列时,新项可能会一直移动到前面。

二、二叉堆操作

我们的二叉堆实现的基本操作如下:

BinaryHeap() 创建一个新的,空的二叉堆。
insert(k) 向堆添加一个新项。
findMin()返回具有最小键值的项,并将项留在堆中。
delMin() 返回具有最小键值的项,从堆中删除该项。
如果堆是空的,isEmpty() 返回true,否则返回 false。
size() 返回堆中的项数。
buildHeap(list) 从键列表构建一个新的堆。

注意,无论我们向堆中添加项的顺序是什么,每次都删除最小的。

为了使我们的堆有效地工作,我们将利用二叉树的对数性质来表示我们的堆。为了保证对数性能,我们必须保持树平衡。平衡二叉树在根的左和右子树中具有大致相同数量的节点,它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。 在我们的堆实现中,我们通过创建一个 完整二叉树 来保持树平衡。 一个完整的二叉树是一个树,其中 每层结点都完全填满,在最后一层上如果不是满的,则只缺少右边的若干结点。 Figure 1 展示了完整二叉树的示例。
完整二叉树的另一个有趣的属性是,我们可以使用单个列表来表示它。

  1. # from pythonds.trees.binheap import BinHeap
  2. class BinHeap:
  3. def __init__(self):
  4. self.heapList = [0]
  5. self.currentSize = 0
  6. def insert(self,k):
  7. '''将项附加到列表的末尾,并通过比较新添加的项与其父项,我们可以重新获得堆结构属性。 '''
  8. self.heapList.append(k)
  9. self.currentSize = self.currentSize + 1
  10. self.percUp(self.currentSize)
  11. def buildHeap(self, alist):
  12. '''直接将整个列表生成堆,将总开销控制在O(n)'''
  13. i = len(alist) // 2
  14. self.currentSize = len(alist)
  15. self.heapList = [0] + alist[:] # 分片法[:]建立一个列表的副本
  16. while (i > 0):
  17. self.percDown(i)
  18. i = i - 1
  19. def percUp(self,i):
  20. '''如果新添加的项小于其父项,则我们可以将项与其父项交换。'''
  21. while i // 2 > 0: # // 取整除 - 返回商的整数部分(向下取整)
  22. if self.heapList[i] < self.heapList[i//2]:
  23. tmp = self.heapList[i // 2]
  24. self.heapList[i // 2] = self.heapList[i]
  25. self.heapList[i] = tmp
  26. i = i // 2
  27. def percDown(self, i):
  28. '''将新的根节点沿着一条路径“下沉”,直到比两个子节点都小。'''
  29. while (i * 2) <= self.currentSize:
  30. mc = self.minChild(i)
  31. if self.heapList[i] > self.heapList[mc]:
  32. tmp = self.heapList[i]
  33. self.heapList[i] = self.heapList[mc]
  34. self.heapList[mc] = tmp
  35. i = mc
  36. def minChild(self, i):
  37. '''在选择下沉路径时,如果新根节点比子节点大,那么选择较小的子节点与之交换。'''
  38. if i * 2 + 1 > self.currentSize:
  39. return i * 2
  40. else:
  41. if self.heapList[i * 2] < self.heapList[i * 2 + 1]:
  42. return i * 2
  43. else:
  44. return i * 2 + 1
  45. def delMin(self):
  46. '''移走根节点的元素(最小项)后如何保持堆结构和堆次序'''
  47. retval = self.heapList[1]
  48. self.heapList[1] = self.heapList[self.currentSize]
  49. self.currentSize = self.currentSize - 1
  50. self.heapList.pop()
  51. self.percDown(1)
  52. return retval
  53. bh = BinHeap()
  54. bh.buildHeap([9,5,6,2,3])
  55. print(bh.delMin())
  56. print(bh.delMin())
  57. print(bh.delMin())
  58. print(bh.delMin())
  59. print(bh.delMin())

关于二叉堆的最后一部分便是找到从无序列表生成一个“堆”的方法。我们首先想到的是,将无序列表中的每个元素依次插入到堆中。对于一个排好序的列表,我们可以用二分搜索找到合适的位置,然后在下一个位置插入这个键值到堆中,时间复杂度为O(logn)。另外插入一个元素到列表中需要将列表的一些其他元素移动,为新节点腾出位置,时间复杂度为O(n)。因此用insert方法的总开销是O(nlogn)。其实我们能直接将整个列表生成堆,将总开销控制在O(n)。Listing 6 所示的是生成堆的操作。

能在O(n)的开销下能生成二叉堆看起来有点不可思议,这里就不做证明了。但要理解用O(n)的开销能生成堆的关键是因为logn因子基于树的高度。而对于buildHeap里的许多操作,树的高度比logn要小。

以上就是python中二叉堆的详细介绍(代码示例)的详细内容,更多请关注Gxl网其它相关文章!

人气教程排行