二叉堆(优先队列)与双端队列【2023年我的编程之旅】

2023,我学习了很多,那么,我就写一个我新学的编程知识——二叉堆(优先队列)与双端队列吧

图片来自网图,涉及侵权请联系我删除

双端队列是什么

双端队列就是一个两端都是结尾的队列,队列的每一端都可以插入数据和移除数据

双端队列是限定插入和删除操作在表的两端进行的线性表,是一种具有队列和栈的性质的数据结构

可以用一个铁道转轨网络来比喻双端队列,在实际使用中,还可以有输出受限的双端队列(即一个端点允许插入和删除,另一个端点只允许插入的双端队列),和输入受限的双端队列(即一个端点允许插入和删除,另一个端点只允许删除的双端队列),而如果限定双端队列从某个端点插入的元素只能从该端点删除,则该双端队列就蜕变为两个栈底相邻的栈了

双端队列怎么用

基本操作与普通队列没啥区别,只不过两边都能进或出罢了

​
    deque<int> que;//创建一个双端队列 que 
	队名.push_front(5);//向前插入5 
	队名.push_back(4);//向后插入4 
	队名.pop_back();//删除队尾 
	队名.pop_front();//删除队头 
	队名.front();//查看队头 
	队名.back();//查看队尾 
	队名.size();//队列元素个数 
	队名.empty();//队列是否为空 
	!队名.empty();//队列不为空

​

以上为用法,头文件为#include<deque>

【电子学会六级·双端队列】

这道题是一个基本双端队列操作问题,只需跟着题目意思做就行了

#include<bits/stdc++.h>//万能头文件
using namespace std;
int main()
{
    int n;//代表测试数据的组数
    int type,c,x,n1;
    cin>>n;
    deque<int> que;//创建双端队列
    for(int i=1;i<=n;i++)
    {
        cin>>n1;//操作次数
        for(int j=1;j<=n1;j++)
        {
            cin>>type;
            if(type==1)//type=1,进队操作
            {
                cin>>x;
                que.push_back(x);
            }
            else//type=2,出队操作
            {
                cin>>c;
                if(!que.empty())//队列不为空的情况下
                {
                    if(c==0)//c=0代表从队头出队
                    {
                       que.pop_front();
                    }
                    else//c=1代表从队尾出队
                    {
                        que.pop_back();
                    }
                }
            }
        }
        if(!que.empty())//队列不为空的情况下
        {
            while(!que.empty())
            {
                cout<<que.front()<<" ";//从对头出队
                que.pop_front();//删除此项
            }
        }
        else//队列为空
        {
            cout<<"NULL";
        }
        cout<<endl;
    }
    return 0;
}

怎么样,你写对了吗?

那么,来一道题练练手吧:

二叉堆(优先队列)是什么

二叉堆分为两个类型:

  1. 大顶堆:
    最大堆的任何一个父节点的值,都大于或等于它左、右孩子节点的值
  2. 小顶堆
    最大堆的任何一个父节点的值,都小于或等于它左、右孩子节点的值

二叉堆注意事项:

一.调整一个二叉堆,变化如下图:

现在这个最小堆明显不符合要求,该怎么调整呢?

如下图:

1.不满足,“上浮”后:

2.依然不满足,继续“上浮”

3.还是不满足,2的位置不对,与3调换位置

4.满足

二.

在二叉堆里我们要求:

最小的元素在顶端(最大的元素在顶端)

每个元素都比它的父节点小(大),或者和父节点相等。

三.

删除元素的过程类似添加元素,只不过添加元素是"向上冒",而删除元素是"向下沉":删除位置1的元素,把最后一个元素移到最前面,然后和它的两个子节点比较,如果两个子节点中较小的节点小于该节点,就将它们交换,直到两个子节点都比此顶点大。

计算两个子节点的位置的公式:左子节点:2K+1、右子节点:2K+2(注:这里针对的是根节点为零的情况,若根为1,则左右分别为2K与2K+1

四.

和添加元素完全一样的过程,只是要注意被修改的元素在二叉堆中的位置

二叉堆如何使用

    priority_queue<int,vector<int>,less<int> > heap;//大顶堆 
	priority_queue<int,vector<int>,greater<int> > heap;//小顶堆 
	堆名.push(x);//将x加入到堆中 
	堆名.pop();//删除堆顶 
	堆堆.top();//查看堆顶 
	堆名.size();//查看堆中元素个数 
	堆名.empty();//堆是否为空

注意!这里需要用到vector!

明白了原理,让我们来做题吧

[NOIP2004 提高组] 合并果子

这道题明显是最小堆,代码来咯: 

​
#include<bits/stdc++.h>
using namespace std;
int main()
{
    priority_queue<int,vector<int>,greater<int>> heap;//创建一个小顶堆
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        int x;
        cin>>x;
        heap.push(x);//将x加入到堆中
    }
    int res=0;
    while(heap.size()!=1)
    {
        int x=heap.top();
        heap.pop();
        int y=heap.top();
        heap.pop();
        res+=x+y;
        heap.push(x+y);
    }
    cout<<res;
    return 0;
}

​

小复习

图(关系结构)

由点和边构成的集合

  • 无向图
  • 有向图

带权图

出度:从一个点出去的边的数量
入度:进入一个点的边的数量

连通图

概念:一个图中所有点之间至少存在一条路径(路径:一个点有一条路到达另一个点)的图
无向图:连通图
有向图
  • 弱连通图:将此图转换为无向图后,是连通状态,即为若连通
  • 强连通图:有向图中任意一点都存在一条到达其余所有点的路径

完全图

一张图中,任意两点之间均有着一条直接连接的边

概念:只有n-1(n为点的数量)条边的连通图
点和点之间的关系
  • 父子
  • 兄弟
  • 祖孙
度:一个点的子节点数量
节点类型
  • 根结点
  • 分支节点
  • 叶子节点

完全二叉树

概念:按照每一层节点依次填充的顺序的二叉树,是完全二叉树
特性:
  • n层的二叉树,最多共有** 2n−12n1个节点**
  • 二叉树第n层,最多有个2n−12n1节点

满二叉树

概念:n层的二叉树中所有分支节点的度数都为2

人生最重要的不是所得到的,而是你付出的

  • 35
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 14
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值