CG2925.特殊的数据结构
【问题描述】
栈和队列是两种最常用的数据结构。本题设计了一种特殊的数据结构,如图所示,它有两个入口,左边的入口记为L,右边的入口记为R,有一个出口。约定只能从入口读入数据,从出口输出数据(相当于两个队列共用一个出口,这两个队列也记为L和R)。
另外,约定该数据结构处理数据的模式为
单位时间内两个入口要么同时读入一个正整数,要么只有一个入口读入一个正整数。
在第1个单位时间内,从出口输出L队列首的数据,在下一个单位时间内输出R队列首的数据,依次交替。如果这个过程中某个队列为空,则该单位时间内转而从另一个队列中输出数据,下一个单位时间仍然从规则中原定的队列输出数据。
每个单位时间内,总是先读入数据,再输出数据。
在本题中,给定两个入口输入数据序列,输出从出口输出的数据序列。
【输入形式】
输入文件中包含多个测试数据。输入文件第1行为整数T,代表测试数据个数。每个测试数据为数据串序列(不超过100个字符),用逗号格开,表示每个单位时间内从两个入口读入的数据;数据串中,如果两个数据都为正整数,则表示该单位时间内从两个入口都读入了整数;如果一个数据为L或R,则表示该单位时间内该数据代表的队列中没有读入正整数。注意,数据中可能有多余的空格,比如逗号之后可能有一个空格,第一个数据串之前、最后一个数据串之后也可能有空格。
测试数据保证最后一个正整数输入之前两个队列不会同时为空(当然,最后当两个队列都为空的时候,应该结束输出了)。
【输出形式】
对于每个测试数据,输出从出口输出的数据序列,每个正整数(包括最后一个正整数)之后输出一个空格。
【样例输入】
1
68 79, L 34, L 45, 17 R, 23 R, 99 66
【样例输出】
68 79 34 45 17 66 23 99
题目浅析
- 题目采用先进先出的原则,所以第一步我们应该考虑的是用队列结构来存储数据。
- 由于输入数据是字符和数字组成的,我们优先考虑使用字符串或者字符数组来存储初始数据。
- 由于输入数据中存在逗号,我们需要在输入的时候要对逗号进行处理
- 注意程序在同一个时刻是要完成先输入至少一个数后再输出一个数的操作,所以输入数据的时间会比输入所花的时间长。
按照道理来说,可以先把数据存储在左右队列中后,在按照规则对数据进行输出,但是不知道为什么不对(后来猜测可能是同时进行输出输出的问题),所以我采用的是在完成输入操作后立即进行输出的操作。
程序流程解析
我以时间T分部分析一下我程序求解的流程。我根据题目假设,T为奇数的时候该左队列输出,T为偶数的时候该右队列输出。
当T=1s的时候:(左队列存在数据,左队列输出数据)
输入后:68 | 79 输出后: | 79
输出值:68
当T=2s的时候:(右队列存在数据,右队列输出数据)
输入后: | 79 34 输出后: | 34
输出值:68 79
当T=3s的时候:(左队列不存在数据,右队列输出数据)
输入后:| 34 45 输出后: | 45
输出值:68 79 34
当T=4s的时候:(右队列存在数据,右队列输出数据)
输入后:17 | 45 输出后: 17 |
输出值:68 79 34 45
当T=5s的时候:(左队列存在数据,左队列输出数据)
输入后:23 17 | 输出后:23 |
输出值:68 79 34 45 17
当T=6s的时候:(右队列存在数据,右队列输出数据)这里个人觉得是关键的一步操作了
输入后:99 23 | 66 输出后:99 23 |
输出值:68 79 34 45 17 66
当T=7s的时候:(左队列存在数据,左队列输出数据)
输入后:99 23 | 输出后:99 |
输出值:68 79 34 45 17 66 23
当T=8s的时候:(右队列不存在数据,右队列输出数据)
输入后:99 23 | 输出后: |
输出值:68 79 34 45 17 66 23 99
程序结构分析
- 我先创建两个队列,左队列q1和右队列q2。以及一个保存初始数据的字符串s,和两个有着特殊作用的字符串s_1和s_2。队列的详细用法问问度娘。
#include<string>
#include<queue>
queue<string> q1;//左队列
queue<string> q2;//右队列
string s_1;//左队列输入
string s_2;//右队列输入
string s;//初始数据的保存
- 对初始数据的预处理。因为初始数据中包涵了逗号这一特殊的字符,我们需要把它给去掉,才能继续下一步操作。
for (int i = 0; i < s.length(); i++) {
if (s[i] == ',')
s[i] = ' ';
}
在这里,我采用的是最原始的for循环语句,当然也可以采用string类的函数来进行操作。我把逗号替换成了空格,至于为什么是空格,跟我下一步要用的函数有关。
- 字符流sstream,有关详细的用法请问度娘
stringstream ss;
ss.str(s);
getline(cin, s);
for (int i = 0; i < s.length(); i++) {
if (s[i] == ',')
s[i] = ' ';
}
.......
if (ss) {
if (ss >> s_1&&ss >> s_2)
{
t_time += 2;
if (s_1 != "L"&&s_1 != "R") q1.push(s_1);
if (s_2 != "L"&&s_2 != "R") q2.push(s_2);
}
}
“stringstream“”能将字符串进行分割,并像“cin”一样挨着把值赋值给另外一个变量,直到数据尾。这里为什么有一个 “getline(cin, s)“”,其实我也解释不太清楚,只是知道如果在我的程序中如果不加入这个需要两个回车才能完成数据的输入。
- 接下来就是同时进行输入和输出的操作了。这里每个的编写代码的想法可能都不一样,就不在详细的解释了。我自己为了更好的调试程序,所以加了很多的没必要的限制条件,本身的代码并没有进行优化。
程序源代码
#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<stdlib.h>
#include<vector>
#include<stack>
#include<fstream>
#include<queue>
#include<sstream>
using namespace std;
int main() {
int n;
queue<string> q1;//左队列
queue<string> q2;//右队列
cin >> n;
cin.get();
while (n--)
{
string s_1;//左队列输入
string s_2;//右队列输入
string s;//初始数据的保存
stringstream ss;
getline(cin, s);
for (int i = 0; i < s.length(); i++) {
if (s[i] == ',')
s[i] = ' ';
}
ss.str("");
ss.str(s);
int t = 1;//作为判断该左队列输出,还是右队列输出的条件
int t_time = 1;
while (t_time--) {
if (ss) {
if (ss >> s_1&&ss >> s_2)
{
t_time += 2;//作为while循环的退出条件
if (s_1 != "L"&&s_1 != "R") q1.push(s_1);
if (s_2 != "L"&&s_2 != "R") q2.push(s_2);
}
}
//输出
if (t == 1) {
t = 2;
if (q1.empty()) {
if (!q2.empty()) {
cout << q2.front() << " ";
q2.pop();
}
}
else
{
cout << q1.front() << " ";
q1.pop();
}
}
else if (t == 2) {
t = 1;
if (q2.empty()) {
if (!q1.empty()) {
cout << q1.front() << " ";
q1.pop();
}
}
else {
cout << q2.front() << " ";
q2.pop();
}
}
}
cout << endl;
}
return 0;
}
特别注意:
- 单位时间内两个入口要么同时读入一个正整数,要么只有一个入口读入一个正整数。
按照题目这个条件来说,当两个队列为空便可以退出循环条件了。但是按照我所想的同一时刻,先输入后输出的流程,就会出现还没有将全部数据输入完成,就可能出现队列为空的情况(每次只输入一个数据,并且输出数据,队列一直是空队列)。在这里我用的time这个变量进行计数,即输入数据多少次,便需要循环多少次。