队列问题归纳

文章介绍了如何使用C++的标准库queue来实现队列,并通过一个具体的例子——约瑟夫问题,展示了如何运用队列解决报数淘汰的问题。程序首先按照规则构建队列,然后模拟报数过程,报到特定数字的孩子出队,直至队列为空,输出淘汰顺序。
摘要由CSDN通过智能技术生成
  • 队列是我们在数据结构中所学的受限制的线性表,符合“先进先出”,常使用在一些“公平”等待的场景中。

  • 在机试中C++的标准库中(#include <queue>)可以进行队列的实现,下列代码使用了队列的常用功能。( push(i)、pop()、front()、empty() )

#include <queue>
#include <cstdio>
using namespace std;
int main(){
    queue<int> myQueue;//初始化队列,元素都是int类型
    for (int i = 0; i < 5; ++i) {
        myQueue.push(i);//入队
    }
    while (true){
        if(myQueue.empty()){//队列是否为空
            printf("myQueue is empty!\n");
            break;;
        }
        printf("front of myQueue is %d\n",myQueue.front());//打印队首元素
        myQueue.pop();//出队
    }
}
  • 例题1 约瑟夫问题

描述

n 个小孩围坐成一圈,并按顺时针编号为1,2,…,n,从编号为 p 的小孩顺时针依次报数,由1报到m ,当报到 m 时,该小孩从圈中出去,然后下一个再从1报数,当报到 m 时再出去。如此反复,直至所有的小孩都从圈中出去。请按出去的先后顺序输出小孩的编号。

输入

每行是用空格分开的三个整数,第一个是n,第二个是p,第三个是m (0 < m,n < 300)。最后一行是:

0 0 0

输出

按出圈的顺序输出编号,编号之间以逗号间隔。

样例输入

8 3 4

0 0 0

样例输出

6,2,7,4,3,5,1,8

题目分析

样例的大意是有8个孩子围成一圈,从3号孩子开始报数,每次数到4,那个孩子就要离开,直至没有孩子。我们可以通过以下的图发现,队首从3开始,8个孩子正好到序号为2的孩子,之后又会重新连到孩子3(循环队列)。

那把问题抽象化后发现:

(1)从序号p开始入队,入队n个,即到序号p-1为止;

        for (int i = p, j = 0; j < n; ++j) {
            //i 用来遍历孩子的编号
            //j 用来记录已经遍历的孩子的数量
            children.push(i);
            ++i;// p->p+1->p+2->...->n->1->...->p-1
            if(i > n){
                i = 1;
            }
        }

(2)要让报数到m的孩子离开,我们可以换种方式书写,即从队首开始报数并出队,若报的不是m,则归队,而报的正好是m,就不归队。

代码示例

//约瑟夫问题
#include <cstdio>
#include <queue>
using namespace std;
int main(){

    int n,p,m;

    while (true){

        scanf("%d%d%d",&n,&p,&m);
        if(n == 0 && p == 0 && m == 0){
            break;
        }
        queue<int> children;//队列中的元素是孩子的编号

        //把 第一轮 要喊编号的孩子排好队
        for (int i = p, j = 0; j < n; ++j) {
            //i 用来遍历孩子的编号
            //j 用来记录已经遍历的孩子的数量
            children.push(i);
            ++i;// p->p+1->p+2->...->n->1->...->p-1
            if(i > n){
                i = 1;
            }
        }

        //喊号的过程
        int num = 1;//将要喊的编号
        while (true){
            int cur = children.front();// cur是队首孩子的编号,喊1
            children.pop();//喊完了,队首出队
            if(num == m){
                //检查一下刚才喊的号码是不是m,是的话不需要归队了,不用push(cur)
                num = 1;//下一个同学喊的号就是1
                if(children.empty()){
                    //最后一个同学出来了
                    printf("%d", cur);
                    break;
                }
                else{
                    //还有同学在喊号
                    printf("%d,",cur);
                }
            }
            else{
                //喊的号码不是m,继续喊2,3,..,m-1
                num = num + 1;
                children.push(cur);//喊的不是m,刚刚出队的重新归队
            }
        }

    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

~許諾~

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

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

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

打赏作者

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

抵扣说明:

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

余额充值