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.依然不满足,继续“上浮”
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−12n−1个节点**
- 二叉树第n层,最多有个2n−12n−1节点