数据结构:堆

  堆是一种图的树形结构,被用于实现“优先队列”(priority queues)。优先队列是一种数据结构,可以自由添加 数据,但取出数据时要从最小值 开始按顺序取出。在堆的树形结构中,各个顶点被称为“结点”(node),数据就存储在这些结点中。

  这就是堆的示例。结点内的数字就是存储的数据。堆中的每个结点最多有两个子结点 。树的形状取决于数据的个数。另外,结点的排列顺序为从上到下,同一行里则为从左到右。
  

  在堆中存储数据时必须遵守这样一条规则:子结点必定大于父结点 。因此,最小值 被存储在顶端的根结点 中。往堆中添加数据时,为了遵守这条规则,一般会把新数据放在最下面一行靠左的位置 。当最下面一行里没有多余空间时,就再往下另起一行,把数据加在这一行的最左端。


添加操作

  往堆里加数字“5”。

  首先寻找新数据的位置。该图中最下面一排空着一个位置,所以将数据加在此处。

在这里插入图片描述

  如果父结点大于子结点,则不符合上文提到的规则,因此需要交换父子结点的位置。

在这里插入图片描述

  这里由于父结点的6大于子结点的5,所以交换了这两个数字。重复这样的操作直到数据都符合规则,不再需要交换为止。

在这里插入图片描述

  现在,父结点的1小于子结点的5,父结点的数字更小,所以不再交换。


删除操作

  从堆中取出数据时,取出的是最上面的数据。这样,堆中就能始终保持最上面的数据最小。

在这里插入图片描述

  由于最上面的数据被取出,因此堆的结构也需要重新调整。

在这里插入图片描述

  按照排列顺序,将最后的数据(此处为6)移动到最顶端。

在这里插入图片描述

  如果子结点的数字小于父结点的,就将父结点与其左右两个子结点中较小 的一个进行交换。

在这里插入图片描述

  这里由于父结点的6大于子结点(右)的5大于子结点(左)的3,所以将左边的子结点与父结点进行交换。重复这个操作直到数据都符合规则,不再需要交换为止。

在这里插入图片描述

  现在,子结点(右)的8大于父结点的6大于子结点(左)的4,需要将左边的子结点与父结点进行交换。

在这里插入图片描述

  这样,从堆中取出数据的操作便完成了。


总结

  堆中最顶端的数据始终最小,所以无论数据量有多少,取出最小值的时间复杂度都为 O ( 1 ) O(1) O(1)

  另外,因为取出数据后需要将最后的数据移到最顶端,然后一边比较它与子结点数据的大小,一边往下移动,所以取出数据需要的运行时间和树的高度成正比。假设数据量为 n n n,根据堆的形状特点可知树的高度为 l o g 2 n log_2n log2n,那么重构树的时间复杂度便为 O ( l o g n ) O(logn) O(logn)

  添加数据也一样。在堆的最后添加数据后,数据会一边比较它与父结点数据的大小,一边往上移动,直到满足堆的条件为止,所以添加数据需要的运行时间与树的高度成正比,也是 O ( l o g n ) O(logn) O(logn)


应用

  如果需要频繁地从管理的数据中取出最小值,那么使用堆来操作会非常方便。比如狄克斯特拉算法,每一步都需要从候补顶点中选择距离起点最近的那个顶点。此时,在顶点的选择上就可以用到堆。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值