堆的有关知识及STL用法

本文介绍了堆(一种数据结构)作为完全二叉树的应用,重点讲解了如何通过增添和删除元素来维护堆的性质,以及STL中的priority_queue接口。添加和删除元素的时间复杂度均为O(logn),优先级队列在实际应用中的使用和构造方法也被详细阐述。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

堆,一种数据结构,实际上是一棵完全二叉树,可以保证在正常添加、删除元素的同时,保证对于二叉树中的每个节点,其左右子节点的优先级均低于自身,这样,树根的元素的优先级永远最高。等价于一个优先级队列,在正常增删元素的情况下,保证队首元素永远是优先级最高的那一个。

堆的增添删除元素的时间复杂度均为O(logn),而查询优先级最高元素的时间为O(n)。

什么是一棵完全二叉树呢?百度百科对其的描述如下:

一棵深度为k的有n个结点的二叉树,对树中的结点按从上至下、从左到右的顺序进行编号,如果编号为i(1≤i≤n)的结点与满二叉树中编号为i的结点在二叉树中的位置相同,则这棵二叉树称为完全二叉树。

 它有一个重要的性质:树中每个节点的位置可以与一个向量数组的下标一一对应。我们将根节点序号设置为1,那么对任一个编号为i的一个节点,它的父节点序号为i/2,而左子节点的序号为2i,右子节点的序号为2i+1 。正因如此,堆的内部数据结构可以用一个Vector存储数据。

那么,如何维护这样的一课树使得其满足要求呢?堆最重要的数据操作为增添/删除栈顶元素,分别如下进行:

1、元素的增添

首先,对于一个堆,我们默认它已经满足了堆的一切特性,即对于任意节点,其优先级均大于任意一个子节点的(对于子树中的任意一个节点都满足)。现在,我们在序列尾部插入一个新元素,堆的特性就被破坏了,如何对其进行维护呢?

首先,我们将末尾元素作为当前节点,并将其与父节点比较。若此时发生错序,即当前节点的优先级高于父节点,我们将其进行对换。以此类推,直到顺序正确或到达根节点。由于对于一棵节点数量为n的完全二叉树,其高度不会超过log2n,因此我们进行一次回溯所需的时间复杂度为O(logn)。

2、堆顶元素的删除

当我们删除堆顶元素时,缺省的元素操作起来较麻烦。因此一种更实际的做法是,我们将堆顶元素与最后一个元素交换,再将交换后的堆的最后一个元素删除。此时,堆顶元素的顺序被打乱,堆不能维持原来的性质,需要进行调整。我们将堆顶元素作为当前元素,并比较其与优先级最高的子节点的优先级大小(否则,若我们将该节点与优先级较小的子节点交换,那么优先级更大的那个节点将变为其优先级较小兄弟的子节点,依然不符合堆的性质),若发生乱序即当前节点的优先级更小,那么我们交换这两个节点,直到符合堆的性质或不存在子节点为止。同1,堆进行堆顶删除的时间复杂度为O(logn)。

3、堆(优先级队列)的STL接口

堆在stl中的名称为priority_queue,需要#include <queue>来进行引用。

其构造方法有两种

(1)priority_queue<T>,此时要求T存在比较运算符bool operator<(const T) const

(2)priority_queue<T,容器container(默认为vector<T>),比较函数cmp(默认为大顶堆,即less<T>,注意当改用小顶堆less<T>时,尖括号和结尾的尖括号需要加一个空格以防被识别为>>运算符) >

主要接口有push(x)插入元素,pop()删除堆顶元素,返回值为void,以及top()返回堆顶元素的值。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

kongtiao_hanry19

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值