A. DS栈—波兰式,逆波兰式
题目描述
表达式有三种表示方法,分别为:
前缀表示(波兰式):运算符+操作数1+操作数2
中缀表示:操作数1+运算符+操作数2
后缀表示(逆波兰式):操作数1+操作数2+运算符
例如:a +b * (c -d ) - e/f
波兰式:-+a*b-cd/ef (运算符在操作数的前面,用递归计算波兰式)
中缀式:a+b*c-d-e/f
逆波兰式:abcd-*+ef/- (运算符在操作数的后面,用栈计算逆波兰式)
中缀表示就是原表达式去掉扣号。
根据表达式求波兰式、逆波兰式都是教材第三章表达式求值的思想。
求波兰式,需要操作数栈(注意不是计算结果入栈,有计算式入栈),运算符栈。区别在于从后往前扫描表达式,‘(’ 换成')','('换成‘)’。栈顶运算符优先级>新读入运算符优先级出栈,教材第三章表3.1中的相同运算符优先级>(从左往右计算)改为<,例如栈顶为‘+‘,新读入的为‘+’,则栈顶优先级<新读入的优先级。
求逆波兰式,只需要运算符栈。操作数直接输出,操作符按表3.1优先级顺序出栈,输出。
输入表达式,求其波兰式和逆波兰式。
输入
测试次数
每组测试数据一行,一个合法表达式
输出
对每组测试数据,输出两行
第一行,表达式的波兰表示
第二行,表达式的逆波兰表示
不同组测试数据间以空行分隔。
输入样例:
2
4+2*3-10/5
12+3*5+(2+10)*5
输出样例:- + 4 * 2 3 / 10 5
4 2 3 * + 10 5 / -+ + 12 * 3 5 * + 2 10 5
12 3 5 * + 2 10 + 5 * +
代码实现:
#include <iostream>
#include <stack>
#include <string>
#include <map>
using namespace std;
// 判断字符是否为运算符
bool is_operator(char c) {
return c == '+' || c == '-' || c == '*' || c == '/';
}
// 获取运算符优先级
int get_priority(char op) {
map<char, int> priority{
{'+', 1}, {'-', 1},
{'*', 2}, {'/', 2}
};
return priority[op];
}
// 将中缀表达式转换为波兰式
string infix_to_prefix(const string& infix) {
string prefix; //波兰式
stack<char> operators; //运算符栈
for (int i = infix.length() - 1; i >= 0; i--) { //从后往前扫描
char c = infix[i];
if (isdigit(c)) {
prefix = c + prefix; //新来的数都加在波兰式的前头
while (i - 1 >= 0 && isdigit(infix[i - 1])) //判断是不是还有数字,并且不超出范围
{
prefix =infix[i-1]+prefix; //如果前面还有数字不是运算符说明是多位数,也按顺序加在波兰式前面
i--;
}
prefix = " " + prefix; //数字加完后就给加个空格隔开
}
else if (c == ')') { //如果有右括号,压进运算符栈
operators.push(c);
}
else if (c == '(') { //遇到了左括号,运算符准备出栈
while (!operators.empty() && operators.top() != ')') {
prefix = operators.top() + prefix; //将运算符逐个加在波兰式前头直至遇到右括号
prefix = " " + prefix; //每加一个运算符就用空格隔开
operators.pop(); //加完的运算符出栈
}
operators.pop(); // 弹出 ')'
}
else if (is_operator(c)) { //新来了纯运算符 + - * /
while (!operators.empty() && get_priority(c) < get_priority(operators.top())) { //运算符栈非空,并且新运算符优先级小于运算符栈栈顶优先级时
prefix = operators.top() + prefix; //让优先级高的加进在波兰式中
prefix = " " + prefix; //加完后照样用空格隔开
operators.pop(); //加完了所以要出栈
}
operators.push(c); //无论优先级是否高低都把它压进运算符栈
}
}
while (!operators.empty()) { //运算符栈剩余的也出栈
prefix = operators.top() + prefix;
operators.pop();
if (!operators.empty()) { //出完栈还没为空时,前面仍需空格
prefix = " " + prefix;
}
}
return prefix;
}
// 将中缀表达式转换为逆波兰式
string infix_to_postfix(const string& infix) {
string postfix;
stack<char> operators;
for (int i = 0;i<infix.length();i++ ){
char c = infix[i];
if (isdigit(c)) {
postfix += c;
while (i + 1 < infix.size() && isdigit(infix[i + 1])) {
postfix += infix[i + 1];
i++;
}
postfix += ' '; // 数字后面需要加一个空格隔开
}
else if (c == '(') {
operators.push(c);
}
else if (c == ')') {
while (operators.top() != '(') {
postfix += operators.top();
postfix += ' '; // 用空格分隔运算符
operators.pop();
}
operators.pop(); // 弹出 '('
}
else if (is_operator(c)) {
while (!operators.empty() && operators.top() != '(' && get_priority(c) <= get_priority(operators.top())) {
postfix += operators.top();
postfix += ' '; // 用空格分隔运算符
operators.pop();
}
operators.push(c);
}
}
while (!operators.empty()) {
postfix += operators.top();
postfix += ' '; // 用空格分隔运算符
operators.pop();
}
if (!postfix.empty()) {
postfix.pop_back(); // 去掉最后一个空格
}
return postfix;
}
int main() {
int t;
cin >> t;
while (t--) {
string infix;
cin >> infix;
cout << infix_to_prefix(infix) << endl;
cout << infix_to_postfix(infix) << endl;
if (t > 0) {
cout << endl; // 每组测试数据间输出一个空行
}
}
}
B. DS队列之银行排队
题目描述
行营业大厅共服务3种客户,类型为A\B\C,大厅分别设置了3个窗口分别服务三种客户,即每个窗口只服务一种客户。现有一批客户来银行办理业务,每个客户都有类型和办理业务时间。每个窗口按照客户到来的顺序进行服务。
编程实现它们的办理流程,请使用C++自带的queue必须使用队列实现,其他方法0分!
队列queue的用法如下:
1.包含头文件:#include <queue>
2.定义一个整数队列对象:queue<int> myQe;
3.定义一个整数队列对象数组:queue<int> myQA[10];
4.入队操作:myQe.push(itemp); //把整数itemp进入队列
5.出队操作:myQe.pop(); //把队头元素弹出队列,注意本操作不获取队头元素
6.获取队头元素: itemp = myQe.front(); // 把队头元素放入itemp中,注意本操作不弹出元素
7.判断队列是否为空:myQe.empty();//队列空则返回true,不空则返回false
输入
第一行输入先输入n表示客户数量
第二行输入每个客户的类型,数据之间用用空格隔开
第三行输入每个客户的办理时间,数据之间用用空格隔开
输出
第一行输出A类客户的平均办理时间
第二行输出B类客户的平均办理时间
第三行输出C类客户的平均办理时间
输入样例:
8
A B C B C A A A
10 20 30 40 50 60 70 80输出样例:
55
30
40
代码实现:
#include <iostream>
#include <queue>
using namespace std;
int main() {
queue <char>band;
int n,time;
int ta = 0, tb = 0, tc = 0;
int sa=0, sb=0, sc = 0;
char ch;
cin >> n;
for (int i = 0; i < n; i++) {
cin >> ch;
band.push(ch);
}
for (int i = 0; i < n; i++) {
cin >> time;
if (!band.empty()) {
if (band.front() == 'A') {
ta += time;
sa++;
band.pop();
}
else if (band.front() == 'B') {
tb += time;
sb++;
band.pop();
}
else if (band.front() == 'C') {
tc += time;
sc++;
band.pop();
}
}
}
cout << ta/sa << endl;
cout << tb / sb << endl;
cout << tc / sc << endl;
return 0;
}
C. DS队列+堆栈--数制转换
题目描述
对于任意十进制数转换为k进制,包括整数部分和小数部分转换。整数部分采用除k求余法,小数部分采用乘k取整法例如x=19.125,求2进制转换
整数部分19, 小数部分0.125 19 / 2 = 9 … 1 0.125 * 2 = 0.25 … 0 9 / 2 = 4 … 1 0.25 * 2 = 0.5 … 0 4 / 2 = 2 … 0 0.5 * 2 = 1 … 1 2 / 2 = 1 … 0 1 / 2 = 0 … 1所以整数部分转为 10011,小数部分转为0.001,合起来为10011.001
提示整数部分可用堆栈,小数部分可用队列实现
注意:必须按照上述方法来实现数制转换,其他方法0分
输入
第一行输入一个t,表示下面将有t组测试数据。
接下来每行包含两个参数n和k,n表示要转换的数值,可能是非整数;k表示要转换的数制,1<k<=16
输出
对于每一组测试数据,每行输出转换后的结果,结果精度到小数点后3位
输入样例:
2
19.125 2
15.125 16输出样例:
10011.001
F.200
代码实现:
#include <iostream>
#include <iomanip>
#include <stack>
#include <queue>
using namespace std;
int main() {
int t, k;
double n;
stack<int> integer;
queue<int> decimal;
cin >> t;
while (t--) {
cin >> n >> k;
int a = (int)n;
double b = n - (int)n;
int sum = 0;
while (a != 0) {
int r;
r = (int)a / k;
integer.push((int)a % k);
a = r;
}
while (sum<3) {
double r = b * k;
b = r-(int)r;
decimal.push((int)r);
sum++;
}
while (!integer.empty()) {
int top=integer.top();
if (k >=10) {
if (top >= 10) {
char t = top - 10 + 'A';
cout << t;
}
else cout << top;
}
else cout << top;
integer.pop();
}
if (int(n) == 0)cout << "0";
cout << '.';
while (!decimal.empty()) {
int front = decimal.front();
if (k >=10) {
if (front >= 10) {
char t = front - 10 + 'A';
cout << t;
}
else cout << front;
}
else cout <<front;
decimal.pop();
}
cout << endl;
}
return 0;
}
D. DS队列--组队列(不使用STL队列)
题目描述
组队列是队列结构中一种常见的队列结构,在很多地方有着广泛应用。组队列是是指队列内的元素分组聚集在一起。组队列包含两种命令:
1、 ENQUEUE,表示当有新的元素进入队列,首先会检索是否有同一组的元素已经存在,如果有,则新元素排在同组的最后,如果没有则插入队列末尾。
2、 DEQUEUE,表示队列头元素出队
3、 STOP,停止操作
注意:不要使用C++自带的队列对象queue。
输入
第1行输入一个t(t<=10),表示1个队列中有多少个组
第2行输入一个第1组的元素个数和数值
第3行输入一个第2组的元素个数和数值
以此类推输入完t组以定义同组元素之后,开始输入多个操作命令(<200),对空的组队列进行操作,例如输入ENQUEUE 100,表示把元素100插入队列
输出
DEQUEUE出队的元素
输入样例:
2
3 101 102 103
3 201 202 203
ENQUEUE 101
ENQUEUE 201
ENQUEUE 102
ENQUEUE 202
ENQUEUE 103
ENQUEUE 203
DEQUEUE输出样例:
101 102 103
代码实现:
#include <iostream>
#include <map>
using namespace std;
class Node
{
public:
int data;
Node* next;
Node() { data = 0; next = NULL; }
};
class Queue
{
private:
Node* front;
Node* rear;
public:
Queue()
{
front = new Node();
rear = new Node();
front = rear;
front->next = NULL;
}
void push(int x)
{
Node* temp = new Node();
temp->data = x;
temp->next = NULL;
rear->next = temp;
rear = temp;
}
bool empty()
{
if (rear == front)
{
return 1;
}
else
{
return 0;
}
}
void pop()
{
if (front != rear)
{
Node* temp = front->next;
front->next = temp->next;
if (rear == temp)
{
rear = front;
}
free(temp);
}
}
int top()
{
return front->next->data;
}
};
int main()
{
int t,data,flag=1;
cin >> t;
map<int, int>all;
Queue* list = new Queue[t];
for (int i = 0; i < t; i++)
{
int n;
cin >> n;
while (n--) {
cin >> data;
all[data] = i;
}
}
string command;
Queue out;
Queue* group = new Queue[t];
while (cin >> command)
{
if (command == "STOP")
{
break;
}
else if (command == "ENQUEUE")
{
cin >> data;
for (int i = 0; i < t; i++)
{
if (group[i].empty() || all[group[i].top()] == all[data])
{
group[i].push(data);
break;
}
}
}
else if (command == "DEQUEUE")
{
for (int i = 0; i < t; i++)
{
if (group[i].empty() == 0)
{
out.push(group[i].top());
group[i].pop();
break;
}
}
}
}
while(!out.empty())
{
if (flag == 1) {
flag = 0;
cout << out.top();
}
else
cout << " " << out.top();
out.pop();
}
cout << endl;
return 0;
}
E. DS队列----银行简单模拟
题目描述
设某银行有A、B两个业务窗口,且处理业务的速度不一样,其中A窗口处理速度是B窗口的2倍 —— 即当A窗口每处理完2个顾客时,B窗口处理完1个顾客。给定到达银行的顾客序列,请按业务完成的顺序输出顾客序列。假定不考虑顾客先后到达的时间间隔,并且当不同窗口同时处理完2个顾客时,A窗口顾客优先输出。
输入
输入为一行正整数,其中第1个数字N(≤1000)为顾客总数,后面跟着N位顾客的编号。编号为奇数的顾客需要到A窗口办理业务,为偶数的顾客则去B窗口。数字间以空格分隔。
输出
按业务处理完成的顺序输出顾客的编号。数字间以空格分隔,但最后一个编号后不能有多余的空格。
输入样例:
8 2 1 3 9 4 11 13 15
输出样例:1 3 2 9 11 4 13 15
实现代码:
#include <iostream>
#include <queue>
using namespace std;
int main() {
int n,no;
cin >> n;
int client[25];
queue<int>qa;
queue<int>qb;
for(int i=0;i<n;i++){
cin >> no;
if (no % 2 == 1) {
qa.push(no);
}
else {
qb.push(no);
}
}
int flag = 0;
while (!qa.empty()) {
if (flag == 0)
{
cout << qa.front();
qa.pop();
}
int sa;
if (flag == 0) sa = 1;
else sa = 2;
while (sa-- && !qa.empty()) {
cout << " "<<qa.front();
qa.pop();
}
if (!qb.empty()) {
cout << " " << qb.front();
qb.pop();
}
flag = 1;
}
while (!qb.empty()) {
if (flag == 0) {
cout << qb.front();
flag++;
}
else cout << " " << qb.front();
qb.pop();
}
cout << endl;
return 0;
}
F. DS队列----银行单队列多窗口模拟
题目描述
假设银行有K个窗口提供服务,窗口前设一条黄线,所有顾客按到达时间在黄线后排成一条长龙。当有窗口空闲时,下一位顾客即去该窗口处理事务。当有多个窗口可选择时,假设顾客总是选择编号最小的窗口。
本题要求输出前来等待服务的N位顾客的平均等待时间、最长等待时间、最后完成时间。
输入
输入第1行给出正整数N(≤1000),为顾客总人数;随后N行,每行给出一位顾客的到达时间
T
和事务处理时间P
,并且假设输入数据已经按到达时间先后排好了顺序;最后一行给出正整数K(≤10),为开设的营业窗口数。输出
在一行中输出平均等待时间(输出到小数点后1位)、最长等待时间、最后完成时间,之间用1个空格分隔,行末不能有多余空格。
输入样例:
9
0 20
1 15
1 61
2 10
10 5
10 3
30 18
31 25
31 2
3
输出样例:6.2 17 62
代码实现:
#include <iostream>
#include <iomanip>
#include <queue>
using namespace std;
class Customer {
public:
int arrive, handle;
Customer(int a, int h) {
arrive = a; handle = h;
}
};
class Windows {
public:
int busy, end;
Windows(){}
Windows(int b, int e)
{
busy = b; end = e;
}
};
int main() {
int n, k, arrive, handle,currentTime=0;
int busy, end;
int waitTime=0,maxwaitTime=-1,allTime=0,finishTime=0;
cin >> n;
queue<Customer> cc;
for(int i=0;i<n;i++) {
cin >> arrive >> handle;
cc.push(Customer(arrive, handle));
}
cin >> k;
Windows* window = new Windows[k];
for (int i = 0; i < k; i++) {
window[i].busy = 0; //空闲
}
while (!cc.empty()) {
for (int i = 0; i < k; i++) {
if (window[i].end == currentTime) {
window[i].busy = 0;
}
}
if (cc.front().arrive <= currentTime) {
for (int i = 0; i < k; i++) {
if (window[i].busy == 0&&(cc.front().arrive <= currentTime)&&(!cc.empty())) {
window[i].busy = 1;
window[i].end = currentTime + cc.front().handle;
waitTime = currentTime - cc.front().arrive;
allTime += waitTime;
if (finishTime < window[i].end) {
finishTime = window[i].end;
}
if (waitTime > maxwaitTime)
maxwaitTime = waitTime;
cc.pop();
}
}
}
currentTime++;
}
cout << fixed << setprecision(1) << (double)allTime / n << " " << maxwaitTime << " " << finishTime << endl;
return 0;
}
G. DS队列——约瑟夫环
题目描述
约瑟夫环:假设 n 个人按编号顺时针从小到大排成一圈(编号为从 1 到 n )。接着约定一个正整数 k,从编号为 1 的人开始顺时针报数(编号为 1 的人报数 1 ,编号为 2 的人报数 2 ……),报到 k 的人离开圈子,然后他的下一个人继续从 1 开始报数,以此类推,直到圈子里只剩下一个人。
请用队列模拟约瑟夫环的报数过程,并按先后顺序输出离开圈子的人最开始的编号。为了统一起见,圈子里的最后一个人也需要离开圈子。
输入
第一行输入 T ,表示 T 个测试用例;
每个测试用例包含两个整数 n、k(1≤n≤100, 1≤k≤100),含义如题目描述所示。
输出
输出 n 个整数,按先后顺序表示离开圈子的的人最开始的编号。
整数之间用空格隔开,行末不允许有多余的空格。
输入样例:
2
6 3
10 10输出样例:
3 6 4 2 5 1
10 1 3 6 2 9 5 7 4 8
代码实现:
#include <iostream>
#include <queue>
using namespace std;
int main() {
int t, n, k, cur = 1;
cin >> t;
queue<int>joseph;
while (t--) {
cin >> n >> k;
for (int i = 1; i <= n; i++) {
joseph.push(i);
}
int flag = 0;
while (!joseph.empty()) {
if (k == cur) {
if (flag == 1) cout << " ";
else flag = 1;
cout << joseph.front();
joseph.pop();
cur = 1;
}
else {
joseph.push(joseph.front());
joseph.pop();
cur++;
}
}
cout << endl;
}
return 0;
}