首页 > 其他分享 >队列(queue)与优先队列(priority_queue)

队列(queue)与优先队列(priority_queue)

时间:2024-07-24 19:29:04浏览次数:13  
标签:priority 优先级 name 队列 元素 queue int

队列

在数据结构中也称为操作受限的线性表,是一种只允许在表的一端插入,在另一端删除的线性表。

相关的几个概念

1)队尾rear:插入端,线性表的表尾;

2)队首front:删除端,线性表的表头;

3)空队列:当队列中没有任何元素时,称为空队列。

特点

先进先出(FIFO,first in first out),就像在食堂排队买饭,排在最前面的先买,后来的排在队尾,即删除在队首,插入在队尾。

queue容器的使用

定义

queue<typedef> name;//typedef可以是任意基本数据类型或容器。

如:queue<int> q;//整型队列容器

queue队列操作

(1) push(x); 将x入队,即将x插入到队尾。

(2)front(x); 获得队首元素。

(3)back(x); 获得队尾元素(这个我感觉不咋用)。

(4)pop(); 弹出队首元素。

(5)empty(); 检测队列是否为空。

(6)size(); 返回队列内元素个数。

例题

林大oj 1632 周末舞会

#include <bits/stdc++.h>//万能头文件
using namespace std;
queue<int>vis1,vis2;//定义两个队列
int main()
{
    int m,n,k;//男士人数m,女士人数n,舞曲数目k
    while(cin>>m>>n)
    {
        cin>>k;
        int v1,v2;
        for(int i=1;i<=m;i++)
          vis1.push(i);//压入队列
        for(int i=1;i<=n;i++)
          vis2.push(i);
        while(k--)
        {
            v1=vis1.front();//获取队首元素
            v2=vis2.front();
            vis1.pop();//队首元素出列
            vis2.pop();
            cout<<v1<<" "<<v2<<endl;
            vis1.push(v1);
            vis2.push(v2);
        }
    }
    return 0;
}

林大oj 1634 约瑟夫环

#include <bits/stdc++.h>
using namespace std;
queue<int>s;
int main()
{
    int n,m;
    cin>>n>>m;
        int k=0,t;
        for(int i=1;i<=n;i++)
            s.push(i);//压入队列
        while(s.size()>1)//只要还有一个及以上的人在,就继续
        {
            k++;
            t=s.front();//取出队首元素
            s.pop();//将队首元素出列
            if(k%m!=0)//检查
                s.push(t);//不是要找的,先放回队列
        }
        cout<<s.front()<<endl;//仅剩下最后一个,打出
    return 0;
}

林大oj 1635 酒桌游戏

#include <bits/stdc++.h>//problem 1635
using namespace std;
queue<int> vis;
map<int,string> mp;//将人名与编码联系起来
map<int,string>::iterator it;//迭代器
int fun(int n)
{
    while(n)
    {
        if(n%10==7)
            return 1;
        n/=10;
    }
    return 0;
}
int main()
{
    int n,m,t,temp;
    string name,ans;
    while(cin>>n>>m>>t)
    {
        mp.clear();
        for(int i=1;i<=n;i++)
            vis.push(i);//将编号压入队列
        for(int i=1;i<=n;i++)
        {
            cin>>name;
            mp[i]=name;//输入人名并将其与编号一一对应
        }
        for(int i=1;i<m;i++)
        {
            vis.push(vis.front());//将第m号人的前面几个人顺次插入队尾
            vis.pop();
        }
        while(vis.size()>1)
        {
            if(fun(t)==1||t%7==0)//检查
            {
                vis.pop();
            }
            else
            {
                vis.push(vis.front());
                vis.pop();
            }
            t++;
        }
        cout<<mp[vis.front()]<<endl;//输出对应编码的人名
    }
    return 0;
}

这个代码用到了map(学会了这个之后我本人非常喜欢用hhh,后面也会出一个关于map使用的文章),有的同学可能还没学到,下面是不使用map的代码。

#include <bits/stdc++.h>
using namespace std;
struct node
{
    int num;
    string name;
}p[1001];//这里不是用map,而是用结构体来记录编号和名字
queue<node>q;//队列用于模拟传递过程
bool judge(int x)
{
    if(x%7==0)
        return 1;
    while(x)
    {
        if(x%10==7)
        return 1;
        x=x/10;
    }
    return 0;
}
int main()
{
    int n,m,t;
    string name;
    cin>>n>>m>>t;
    for(int i=1;i<=n;i++)
    {
        cin>>p[i].name;
        p[i].num=i;
    }
    for(int i=1;i<=n;i++)
        q.push(p[i]);
    for(int i=1;i<=m-1;i++)
    {
        q.push(p[i]);
        q.pop();
    }
    while(q.size()>1)
    {
        node tmp=q.front();
        q.pop();
        if(!judge(t))
            q.push(tmp);
            t++;
    }
/*在这个循环中,每次从队列中取出队首的人物信息 tmp,
然后检查 t 是否满足 judge(t) 的条件。如果不满足条件,
则将 tmp 放回队列尾部,并将 t 自增。
直到队列中只剩下一个人满足条件时,循环结束。*/
    printf("%s\n",q.front().name.c_str());
    return 0;
}

关于参数 q.front().name.c_str()

  • q.front() 是队列 q 中的第一个元素,类型是 node 结构体。
  • name 是 node 结构体中的一个成员变量,类型是 string,用来存储参与者的名字。
  • .c_str() 是 string 类的成员函数,用于返回一个指向以空字符结尾的C风格字符串的指针(即 const char* 类型)。
  • printf("%s\n", q.front().name.c_str()); 的作用是将队列 q 中第一个人物的名字以C风格的字符串形式输出到标准输出(通常是控制台)。
  • %s 接收 q.front().name.c_str() 返回的字符串指针,并将其输出。

林大oj 1633 取牌游戏

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+1;
queue<int>vis;//创建队列模拟牌堆
int a[N];
int main()
{
    int n,k,p,num=0,q=0;
/*n表示玩家数,k表示牌数,p表示每次移动的牌数,
num用于计数,q用于记录“good”牌的位置*/
    cin>>n>>k>>p;
    for(int i=1;i<=k;i++)
    vis.push(i);
    while(!vis.empty())
    {
        int tmp=vis.front();
        vis.pop();
        num++;
        if(num%n==0)//从队列首部取出一张牌,若该牌是"good",将其位置记录在数组a中。
            a[q++]=tmp;
        if(!vis.empty())
            for(int i=1;i<=p;i++)//将p张牌一张张顺次移动到最后,放在牌堆底部
        {
            int tp=vis.front();
            vis.pop();
            vis.push(tp);
        }
    }
    sort(a,a+k/n);//对数组a进行排序,以便输出时是按照升序的
    for(int i=0;i<k/n;i++)//输出数组a中的所有元素,即"good"牌的位置
        cout<<a[i]<<endl;
    return 0;
}
/*由于题目中k是n的倍数,所以“good”牌的数量m就是k除以n的结果*/

优先队列

优先队列(Priority Queue)是一种特殊的队列数据结构,它与普通队列的主要区别在于每个元素都关联有一个优先级。在优先队列中,元素按照优先级的高低进行排列,而不是严格按照它们被插入的顺序。

定义

priority_queue<typename> name;

//typename可以是任意基本数据类型或容器,按照降序对队列元素排序。

如:priority_queue<int> pq;//整型降序优先队列

注:优先级队列默认使用vector作为其底层存储数据的容器, 在vector上又使用了堆算法将vector中元素构造成堆的结构,因此priority_ queue就是堆,所有需要用到堆的位置,都可以考虑使用priority_ queue 。

常见操作

(1)push(x); 将x插入到优先队列中。加入元素后会自动调整priority_ queue的内部结构以保证队首元素(堆顶元素)的优先级最高。

(2)top(); 获取队首元素,即优先级最高元素(优先队列没有front和back函数哟~)。

(3)pop(); 令队首元素出队,出队后会调整堆内部结构。

(4)empty(); 检测优先队列内部是否为空。

(5)size(); 返回优先队列内的元素个数。

优先队列元素优先级的设置

定义优先队列内元素的优先级是运用好优先队列的关键,以基本数据类型和结构体类型为例:

基本数据类型的优先级设置:


优先队列默认是数字大的优先级越高,以int为例,以下两个语句等价:

priority_ queue<int> pq;
priority_ queue <int, vector<int>, less<int> > pq;

// 注意> >之间的空格。

参数vector<int>填写的是来承载底层数据结构堆的容器
less <int>是对第一个参数int的比较类,less <int>表示数字大的优先级越大,而greater<int>表示数字小的优先级越大。想让优先队列总是把最小的的元素放在队首,则使用语句:

priority_ queue <int, vector <int>, greater<int> > pq;

例题 林大oj 1688 合并果子

例如有 3 种果子,数目依次为 1 , 2 , 9 。可以先将 1 、 2 堆合并,新堆数目为 3 ,耗费体力为 3 。接着,将新堆与原先的第三堆合并,又得到新的堆,数目为 12 ,耗费体力为 12 。所以多多总共耗费体力 =3+12=15 。可以证明 15 为最小的体力耗费值。

#include <bits/stdc++.h>
using namespace std;
priority_queue<int,vector<int>,greater<int> >v;//这句是从小到大排序,也可以用结构体排序
int main()
{
    ios::sync_with_stdio(0);
    int n,a,b,sum=0,x;
    cin>>n;
    for(int i=0;i<n;i++)
    {
        cin>>x;
        v.push(x);
    }
    while(v.size()>=2)
    {
       a=v.top();v.pop();
       b=v.top();v.pop();
       v.push(a+b);
       sum+=a+b;
    }
    cout<<sum<<endl;
    return 0;
}

结构体的优先级设置

重载结构体变量"<”"和“>”关系运算符,实现结构体变量的比较
less调用”<"运算符,greater 调用">” 运算符

注:如果题目中只需要利用小数优先级高的情形,可以把”<"运算符的实现修改为”>”的比较方法,这样就不需要用greater了,只用默认的less就可以了。但是,容易引起歧义。

这里介绍一下operator < 重载的写法:
主要决定着你的变量或者结构体在优先队列中是升序还是降序排列的!

#include <bits/stdc++.h>
using namespace std;
struct sa{
int x;
};
bool operator < (const sa &a,const sa &b)//这里的< 一直不变
{
    return a.x>b.x;  //这里的> <决定是升序还是降序,>号升序,< 降序
}
priority_queue <sa> vis;
int main()
{
for(int i=1;i<=10;i++)
vis.push({i});
sa tmp;
while(!vis.empty())
{
    tmp=vis.top();
    cout<<tmp.x<<endl;
     vis.pop();
}
return 0;
}

例题 林大oj 1537 买饭

有n个人在一个卖饭窗口前排队买饭,假如每个人买饭的时间为t,请编程找出一种这n个人排队的顺序,使得这n个人的平均等待时间最小。

#include <bits/stdc++.h>
using namespace std;
struct sa
{
    int time;
    int id;
 };
bool operator < (const sa &a,const sa &b)
{
    if (a.time!=b.time)
    return a.time>b.time;
    else
        return a.id>b.id;
}
priority_queue<sa>vis;

int main()
{
   int n,x;
   double sum=0.0;
   cin>>n;
   for(int i=1;i<=n;i++)
   {
       cin>>x;
       vis.push({x,i});//x是time,i是id,结构体用花括号
   }
   struct sa tmp;
   for(int i=1;i<=n;i++)
   {
     tmp=vis.top();
     if (i!=n)
     cout<<tmp.id<<" ";
     else
        cout<<tmp.id<<endl;
     sum+=(n-i)*tmp.time;//n-i表示当前人后面还有几个人,tmp.time表示当前人的买饭时间
     vis.pop();
   }
   printf("%.2lf\n",sum/n);
    return 0;
}

考试太多,很久没有更新了,这一篇也是断断续续的写了很久hhh(草稿堆里还有一大堆半成品2333),感觉后半段写的挺潦草的。。。如有问题,欢迎指出交流,祝各位天天开心~

标签:priority,优先级,name,队列,元素,queue,int
From: https://blog.csdn.net/2302_79459176/article/details/138765753

相关文章

  • 单调队列-滑动窗口最大值
    题目:给你一个整数数组nums,有一个大小为k的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的k个数字。滑动窗口每次只向右移动一位。返回滑动窗口中的最大值。思路:通过双端队列,因为只看得到k个数字,所以先在队列放入k个数字,并且每次放入时都要将他与......
  • Python 中的工作队列 - 我错过了什么吗?
    这可能会被标记为重复或可能不相关。但我实际上相信这个问题对我和未来缺乏经验的Python开发人员都很重要。由于GIL,用于CPU密集型任务的本地工作队列的概念在Python中至关重要。这方面SE上有明显的答案。使用子进程的方法来绕过缺乏真正的CPU有限并行性的问题。在Pyth......
  • [atcoder utpc2023_p] Priority Queue 3
    PriorityQueue3题意:有一个小根堆和\(1\)~\(n\)个数,以及一个操作序列,+表示\(push\),-表示\(pop\),\(pop\)有\(m\)次,问你有多少种插入顺序使得最后的pop集合与给出的的数字集合\(Y\)相同。首先有个浅显的发现:对于不在\(Y\)集合中的数,可选范围形如一个阶梯,换句话......
  • Python 类型暗示​​一个充满 myclass 对象的双端队列
    使用Python3.6或更高版本,我想输入提示一个返回MyClass对象的函数myfunc我如何提示myqueue是一个deque|||充满MyClass对象?objects?fromcollectionsimportdequeglobal_queue=deque()classMyClass:passdefmyfunc(m......
  • Java中的优先级队列(PriorityQueue)(如果想知道Java中有关优先级队列的知识点,那么只看这
        前言:优先级队列(PriorityQueue)是一种抽象数据类型,其中每个元素都关联有一个优先级,元素按照优先级顺序进行处理。✨✨✨这里是秋刀鱼不做梦的BLOG✨✨✨想要了解更多内容可以访问我的主页秋刀鱼不做梦-CSDN博客先让我们看一下本文大致的讲解内容:目录1.优......
  • 【数据结构】队列详解和模拟实现
    大家好,今天我们学习队列,本篇博客主要涉及一般队列,环形队列和双端队列,每个队列应用场景均有所差异,下面我们一起来看看吧。队列(Queue)一,概念队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出的特性入队列:进行插入操作的一端称为队尾(Ta......
  • 单调队列优化DP
    通法:写的时候要灵活变通(可以考虑类似于双指针的技巧,如跳房子)。P3957[NOIP2017普及组]跳房子套个二分,然后由于与位置相关,所以维护一个左端点和右端点,右端点考虑最短步长会不会跳过头,左端点考虑最长步长会不会跳不到。修剪草坪满足连续性质,所以一次考虑一段,\(f_i\)保证\(......
  • 数据结构----队列中的链式队列
     目录 链式队列       1.1逻辑结构:线性结构       1.2存储结构:链式存储      1.3链式队列的操作:                        (1)创建一个空的队列                (2)入列     ......
  • C语言-栈和队列
    文章目录......
  • 单调队列优化 && 斜率优化
    单调队列优化dp浅学1.概念单调队列优化的本质是借助单调性,及时排除不可能的决策,保持候选集合的秩序性。2.例题P1714切蛋糕题目大意:给定一个序列,找出长度不超过\(m\)的连续子序列,使得子序列中所有数的和最大。思路:要求区间和,首先求出前缀和,然后考虑朴素dp,不难想到......