数据结构实验---栈、队列

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;
}

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值