概念

  • 队列有一个重要的变体,叫作优先级队列。

    • 和队列一样,优先级队列从头部移除元素,不过元素的逻辑顺序是由优先级决定的。
    • 优先级最高的元素在最前,优先级最低的元素在最后。
  • 实现优先级队列的经典方法是使用叫作二叉堆(Binary Heap)的数据结构。
    • 二叉堆的入队操作和出队操作均可达到O(log n)。
    • 其逻辑结构上像二叉树, 却是用非嵌套的列表来实现的
    • 二叉堆有两个常见的变体:
      • 最小堆(最小的元素一直在队首)
      • 最大堆(最大的元素一直在队首)

二叉堆的操作

  • BinaryHeap()新建一个空的二叉堆。

  • insert(k)往堆中加入一个新元素。

  • findMin()返回最小的元素,元素留在堆中。

  • delMin()返回最小的元素,并将该元素从堆中移除。

  • isEmpty()在堆为空时返回True,否则返回False。

  • size()返回堆中元素的个数。

  • buildHeap(list)根据一个列表创建堆。

用非嵌套列表实现二叉堆

结构属性

  • 为了使堆操作能保持在对数水平上, 就必须采用二叉树结构;
  • 同样, 如果要使操作始终保持在对数数量级上, 就必须始终保持二叉树的“平衡”
    • 树根左右子树拥有相同数量的节点
    • 我们采用“完全二叉树”的结构来近似实现“平衡”

      完全二叉树,叶节点最多只出现在最底层和次底层,而且最底层的叶节点都连续集中在最左边,每个内部节点都有两个子节点, 最多可有1个节点例外

      • 下标为p
      • 左子节点下标为2p
      • 右子节点为2p+1
      • 父节点下标为p//2

堆次序 Heap Order

  • 任何一个节点x, 其父节点p中的key均小于x中的key

    这样,符合“堆”性质的二叉树,其中任何一条路径,均是一个已排序数列, 根节点的key最小

二叉堆操作的实现

二叉堆初始化

  • 采用一个列表来保存堆数据,其中表首下标为0的项无用,但为了后面代码可以用到简单的整数乘除法,仍保留它。
  1. class BinHeap:
  2. def __init__(self):
  3. self.heapList=[0]
  4. self.currentSize=0

insert(key)方法

  • 新key加在列表末尾,显然无法保持“堆”次序虽然对其它路径的次序没有影响,但对于其到根的路径可能破坏次序
  • 需要将新key沿着路径来“上浮”到其正确位置
  • 注意:新key的“上浮”不会影响其它路径节点的“堆”次序

  1. # 上浮
  2. def percUp(self, i):
  3. while i//2 > 0:
  4. if self.heapList[i] < self.heapList[i//2]:
  5. self.heapList[i], self.heapList[i //
  6. 2] = self.heapList[i//2], self.heapList[i]
  7. i = i//2
  8. def insert(self, k):
  9. self.heapList.append(k)
  10. self.currentSize += 1
  11. self.percUp(self.currentSize)

delMin()方法

  • 移走整个堆中最小的key:根节点heapList[1]
  • 为了保持“完全二叉树”的性质,只用最后一个节点来代替根节点.
    • 将新的根节点沿着一条路径“下沉”,直到比两个子节点都小
    • “下沉”路径的选择:如果比子节点大,那么选择较小的子节点交换下沉

  1. def percDown(self, i):
  2. while(i*2) <= self.currentSize:
  3. mc = self.minChild(i)
  4. if self.heapList[i] > self.heapList(mc):
  5. self.heapList[i], self.heapList[mc] = self.heapList[mc], self.heapList[i]
  6. i = mc
  7. def minChild(self, i):
  8. if i*2+1 > self.currentSize:
  9. return i*2
  10. else:
  11. if self.heapList[i*2] < self.heapList[i*2+1]:
  12. return i*2
  13. else:
  14. return i*2+1
  15. def delMin(self):
  16. retval = self.heapList[1]
  17. self.heapList[1] = self.heapList[self.currentSize]
  18. self.currentSize -= 1
  19. self.heapList.pop()
  20. self.percDown(1)
  21. return retval

buildHeap(lst)方法:从无序表生成“堆”

  • 用insert(key)方法,将无序表中的数据项逐个insert到堆中,但这么做的总代价是O(nlog n)
  • 其实,用“下沉”法,能够将总代价控制在O(n)

  1. def buildHeap(self, alist):
  2. i = len(alist)//2
  3. self.currentSize = len(alist)
  4. self.heapList = [0]+alist[:]
  5. print(len(self.heapList), i)
  6. while(i > 0):
  7. print(self.heapList, i)
  8. self.percDown(i)
  9. i -= 1
  10. print(self.heapList, i)

堆排序

  • “堆排序”算法: O(nlog n)

二叉堆列表实现完整代码

  1. class BinHeap:
  2. def __init__(self):
  3. self.heapList = [0]
  4. self.currentSize = 0
  5. # 上浮
  6. def percUp(self, i):
  7. while i//2 > 0:
  8. if self.heapList[i] < self.heapList[i//2]:
  9. self.heapList[i], self.heapList[i //
  10. 2] = self.heapList[i//2], self.heapList[i]
  11. i = i//2
  12. def insert(self, k):
  13. self.heapList.append(k)
  14. self.currentSize += 1
  15. self.percUp(self.currentSize)
  16. def percDown(self, i):
  17. while(i*2) <= self.currentSize:
  18. mc = self.minChild(i)
  19. if self.heapList[i] > self.heapList(mc):
  20. self.heapList[i], self.heapList[mc] = self.heapList[mc], self.heapList[i]
  21. i = mc
  22. def minChild(self, i):
  23. if i*2+1 > self.currentSize:
  24. return i*2
  25. else:
  26. if self.heapList[i*2] < self.heapList[i*2+1]:
  27. return i*2
  28. else:
  29. return i*2+1
  30. def delMin(self):
  31. retval = self.heapList[1]
  32. self.heapList[1] = self.heapList[self.currentSize]
  33. self.currentSize -= 1
  34. self.heapList.pop()
  35. self.percDown(1)
  36. return retval
  37. def buildHeap(self, alist):
  38. i = len(alist)//2
  39. self.currentSize = len(alist)
  40. self.heapList = [0]+alist[:]
  41. print(len(self.heapList), i)
  42. while(i > 0):
  43. print(self.heapList, i)
  44. self.percDown(i)
  45. i -= 1
  46. print(self.heapList, i)

【数据结构与算法Python版学习笔记】树——利用二叉堆实现优先级队列的更多相关文章

  1. 【数据结构与算法Python版学习笔记】目录索引

    引言 算法分析 基本数据结构 概览 栈 stack 队列 Queue 双端队列 Deque 列表 List,链表实现 递归(Recursion) 定义及应用:分形树.谢尔宾斯基三角.汉诺塔.迷宫 优化 ...

  2. 【数据结构与算法Python版学习笔记】引言

    学习来源 北京大学-数据结构与算法Python版 目标 了解计算机科学.程序设计和问题解决的基本概念 计算机科学是对问题本身.问题的解决.以及问题求解过程中得出的解决方案的研究.面对一 个特定问题,计 ...

  3. 【数据结构与算法Python版学习笔记】树——平衡二叉搜索树(AVL树)

    定义 能够在key插入时一直保持平衡的二叉查找树: AVL树 利用AVL树实现ADT Map, 基本上与BST的实现相同,不同之处仅在于二叉树的生成与维护过程 平衡因子 AVL树的实现中, 需要对每个 ...

  4. 【数据结构与算法Python版学习笔记】树——二叉查找树 Binary Search Tree

    二叉搜索树,它是映射的另一种实现 映射抽象数据类型前面两种实现,它们分别是列表二分搜索和散列表. 操作 Map()新建一个空的映射. put(key, val)往映射中加入一个新的键-值对.如果键已经 ...

  5. 【数据结构与算法Python版学习笔记】图——骑士周游问题 深度优先搜索

    骑士周游问题 概念 在一个国际象棋棋盘上, 一个棋子"马"(骑士) , 按照"马走日"的规则, 从一个格子出发, 要走遍所有棋盘格恰好一次.把一个这样的走棋序列 ...

  6. 【数据结构与算法Python版学习笔记】递归(Recursion)——定义及应用:分形树、谢尔宾斯基三角、汉诺塔、迷宫

    定义 递归是一种解决问题的方法,它把一个问题分解为越来越小的子问题,直到问题的规模小到可以被很简单直接解决. 通常为了达到分解问题的效果,递归过程中要引入一个调用自身的函数. 举例 数列求和 def ...

  7. 【数据结构与算法Python版学习笔记】树——相关术语、定义、实现方法

    概念 一种基本的"非线性"数据结构--树 根 枝 叶 广泛应用于计算机科学的多个领域 操作系统 图形学 数据库 计算机网络 特征 第一个属性是层次性,即树是按层级构建的,越笼统就越 ...

  8. 【数据结构与算法Python版学习笔记】树——二叉树的应用:解析树

    解析树(语法树) 将树用于表示语言中句子, 可以分析句子的各种语法成分, 对句子的各种成分进行处理 语法分析树 程序设计语言的编译 词法.语法检查 从语法树生成目标代码 自然语言处理 机器翻译 语义理 ...

  9. 【数据结构与算法Python版学习笔记】树——树的遍历 Tree Traversals

    遍历方式 前序遍历 在前序遍历中,先访问根节点,然后递归地前序遍历左子树,最后递归地前序遍历右子树. 中序遍历 在中序遍历中,先递归地中序遍历左子树,然后访问根节点,最后递归地中序遍历右子树. 后序遍 ...

随机推荐

  1. 洛谷P1925 最大划分乘积的数学解法

    题目 最大划分乘积 题解 这道题用到一点导数和数论的知识,很容易看出这道题是求函数 \[f(x)=(\frac{n}{x})^{x} \] ( \(x\) 为正整数)的最大值.我们可以对 \(ln(f ...

  2. Django——ORM打印SQL

    如果想打印ORM转换过程中的SQL,需要在settings.py中进行如下配置: LOGGING = { 'version': 1, 'disable_existing_loggers': False ...

  3. SpringMVC-初见

    目录 什么是SpringMVC? DispatcherServlet 第一个MVC程序 配置版 Maven可能存在资源过滤的问题 注解版 RestFul和控制器 实现Controller接口 使用注解 ...

  4. ecshop 首页调用指定分类下的销售排行

    /*首页调用指定分类下的销售排行*/ function get_cats_top10($cat = '') { $sql = 'SELECT cat_id, cat_name ' . 'FROM ' ...

  5. Docker系列(19)- 数据卷之Dockerfile

    初识Dockerfile Dockerfile就是用来构建docker镜像的构建文件!命令脚本! 通过这个脚本生成镜像,镜像是一层一层的,脚本与一个个的命令,每个命令都是一层! # 创建一个docke ...

  6. python学习笔记(十三)-python对Excel进行读写修改操作

    日常工作中会遇到Excel的读写问题.我们可以使用xlwt 模块将数据写入Excel表格,使用xlrd 模块从Excel读取数据,使用xlutils模块和xlrd模块结合对Excel数据进行修改.下面 ...

  7. django把变量变成字段进行搜索

    from ceshi.models import Student     #引入model中的模型 获取前端请求的参数 searchKey=request.GET.get("key" ...

  8. 由浅入深了解cookie

    什么是 Cookie "cookie 是存储于访问者的计算机中的变量.每当同一台计算机通过浏览器请求某个页面时,就会发送这个 cookie.你可以使用 JavaScript 来创建和取回 c ...

  9. web带宽估算方法

    每个连接约占用10Kb的带宽,以3万总用户数和10%的在线率计算,并按照10%的冗余率,服务器总带宽=每秒总连接数*10Kbps /(1-冗余率)/1024. 带宽占用(Mbps)=30000*10% ...

  10. php备份mysql 数据库

    1.新建php文件 <?phpheader('Content-Type:text/html;charset=utf8'); ini_set("max_execution_time&qu ...