排队取奶茶

前言

本节课我们会来学习队列这一数据结构,主要包括以下内容

  • 队列的基本概念(队头、队尾)和特点(先入先出)

  • 入队、出队、获取队头元素和判断队列是否为空等基本操作

  • queue的定义和使用

队列

关于队列的更多介绍,可以移步至代码随想录官方网站查看

队列,顾名思义,和排队的队列结构是类似的,在排队的过程中,想要加入队列,需要在队伍的最后一位(也被称为队尾)入队,想要离开队列,需要从队伍的第一位(也被称为队头)出队。

image-20230914160949705

从图中可以看出,队列在队尾那一侧进行插入操作(入队),在队头那一侧进行删除操作(出队),而且是先进先出FIFO(最先进入队列的元素将首先被移除)。

队列在计算机领域中应用也十分广泛,比如在网络通信中,请求和响应通常以队列的形式进行排队,以确保数据按照正确的顺序进行传输,又比如说不同进程可以通过消息队列来传递数据和消息。

队列的操作

在C++中,你可以使用标准库提供的 std::queue 来创建和操作队列,不过这需要引入头文件queue

// 引入queue头文件
#include <queue>

创建一个队列和创建一个栈的写法是相似的,需要指定队列中元素的类型,不过这也意味着队列中的元素必须是相同的数据类型,下面的代码表示创建一个字符串类型的队列。

queue<string> q; // 创建一个字符串类型的队列

队列的常用操作主要有以下几种:

  • empty(): 判断队列是否为空,如果队列为空返回true, 否则返回false

  • push(): 入队操作,将新的元素添加到队列的尾部。

  • pop(): 出队操作,移除队列的头部元素。

  • front(): 访问队列的头部元素,但不会将其移除。

  • size(): 获取队列的长度,即队列中元素的数量。

q.push("Jack");
q.push("Mike");  // 入队了两个名称字符串

q.pop(); // 移除队列头部的元素

string name = q.front(); // 获取队列头部的元素但是不会将其移除

bool isEmpty = q.empty(); //  如果队列为空,返回true;否则返回false

int queueSize = q.size(); // 获取队列中元素的数量

代码编写

照例,先把代码的基础结构搭建好,在使用队列前需要引入头文件queue

#include <iostream>
#include <queue>  // 引入头文件queue
#include <string> // 队列中的元素是字符串类型,需要引入头文件
using namespace std;
int main() {
  int n; // 表示有n个人
  cin >> n; // 输入n
     string name; // 排队队列中人的姓名
}

在循环开始前需要创建一个字符串队列,然后在n次循环中将这n个人的姓名推入到队列中

queue<string> q; // 创建一个队列,用于存储输入的字符串名称
while (n--) { // n次循环
    cin >> name; // 输入姓名
    q.push(name); // 使用push操作将名称推送到队列中
}

队列已经构建完毕,接下来需要接收数字m和m个整数的输入,表示取奶茶的操作,如果数字为1,表示有人取走了奶茶,即出队操作,如果数字为2,表示有人新加入了奶茶队列,即入队操作,这种“如果”的条件,需要使用到if-else结构

cin >> m;  // 输入m, 表示m次操作,不要忘记提前定义m变量
while (m--) { // m次循环
    cin >> opt; // opt表示输入的操作,1表示出队,2表示入队,需要提前定义opt变量
    if (opt == 1 && !q.empty())  { // 注意这里队列为空就不能再弹出了,所以要判断是否为空
      q.pop(); // 出队操作
    } else { 
        cin >> name;
        q.push(name); // 入队操作
    }
}

注意上述操作中,需要考虑出队操作中队列是否为空的情况,当且仅当“操作指令为出队,队列中的元素不为空,即q.empty()为false时”才能出队。

当删除数据结构中的元素时,都应该考虑结构中元素是否已经为空的情况。

当执行完所有操作后,如果队列为空,说明没有取奶茶的人,输出 “There are no more people in the queue..”, 如果仍有元素,则输出下一个取奶茶的人。

if (q.empty()) { // 如果队列为空,输出对应的语句
  cout << "There are no more people in the queue." << endl;
} else { // 如果队列不为空,输出队头元素
    cout << q.front() << endl; // 使用front()操作,获取队头
}

完整的代码如下:

#include <iostream>
#include <queue>
#include <string>
using namespace std;
int main() {
    int n, m, opt; // n代表队列长度,m代表操作次数,opt代表输入指令
    string name;
    cin >> n;
    queue<string> q; // 新建一个队列
    while (n--) {
        cin >> name;
        q.push(name); // push操作入队
    }
    cin >> m;
    while (m--) {
        cin >> opt;
        // 注意这里如果队列已经为空就不能再弹出了,所以要判断是否为空
        if (opt == 1 && !q.empty()) q.pop(); // pop操作出队
        else {
            cin >> name;
            q.push(name);
        }
    }
  // empty操作判断队列是否为空
    if (q.empty()) cout << "There are no more people in the queue." << endl;
    else cout << q.front() << endl; // front操作取出队头元素
} 

总结

本节课中,我们通过一道编程题练习了队列的基本操作,并对队列先入先出的特点有了初步的认识。

那队列和上一节课中学习到的栈之间有什么区别呢?

总结来说,栈是只能在尾部进行插入和删除操作的数据结构,队列是在尾部进行插入操作、头部进行删除操作的数据结构。

对于栈和队列的介绍就到这里了,但是栈和队列的算法题目并不少,大家可以到代码随想录官方网站栈和队列专题查看更多的内容。

不会做游戏!