(七)王道机试指南___栈的应用

算例一

  • 题目描述

  • 解题思路

①括号匹配是典型的问题,要点是:遍历的每一个右括号都会和它左边最近的左括号相匹配

②遇到左括号,压入栈;遇到右括号,栈弹出

  • 解题代码

#include <stdio.h>
#include <stack>
using namespace std;
stack<int> S; //定义一个堆栈
char str[110]; //保存输入字符串
char ans[110]; //保存输出字符串
int main() {
	while (scanf("%s", str) != EOF) { //输入字符串
		int i;
		for (i = 0; str[i] != 0; i++) { //从左到右遍历字符串
			if (str[i] == '(') { //若遇到左括号
				S.push(i); //将其数组下标放入堆栈中
				ans[i] = ' '; //暂且将对应的输出字符串位置改为空格
			}
			else if (str[i] == ')') { //若遇到右括号
				if (S.empty() == false) { //若此时堆栈非空
					S.pop(); / / 栈顶位置左括号与其匹配, 从栈中弹出该已经匹配的左括号
						ans[i] = ' '; //修改输出中该位置为空格
				}
				else ans[i] = '?'; //若堆栈为空,则无法找到左括号与其匹配,修改输出
				中该位置为 ?
			}
			else ans[i] = ' '; //若其为其它字符,与括号匹配无关,则修改输出为空格
		}
		while (!S.empty()) { //当字符串遍历完成后,尚留在堆栈中的左括号无法匹配
			ans[S.top()] = '$'; //修改其在输出中的位置为$
			S.pop(); //弹出
		}
		ans[i] = 0; //为了使输出形成字符串,在其最后一个字符后添加一个空字符
		puts(str); //输出原字符串
		puts(ans); //输出答案字符串
	}
	return 0;
}

或者(这个是不是更通俗易懂一些?)

#include<stdio.h>
#include<stack>
using namespace std;

char str[110];
stack<int> S;

int main() {
	int a[110] = {0};
	while (scanf("%s", &str) != EOF) {
		int i;
		for ( i = 0;i < 100;i++) {
			if (str[i] == '(') {
				S.push(i);
				a[i] = 1;
			}
			else if (str[i] == ')') {
				if (S.empty()) {
					a[i] = 2;
				}
				else {
					int k = S.top();
					a[k] = 0;
					S.pop();
				}
			}
			else {
			}
		}

		printf("%s\n", str);
		for (int p = 0;p <= i;p++) {
			if (a[p] == 1) {
				printf("$");
			}
			else if (a[p] == 2) {
				printf("?");
			}
			else {
				printf(" ");
			}
		}
		printf("\n");
	}
	return 0;
}
  • 注意点

①数组创建大一点总归没坏处

②接受一串字符串:char str[10]; scanf("%s",&str);

算例二

  • 题目描述

  • 解题思路

①思路流程:

  • 解题代码

#include <stack>
#include <stdio.h>
using namespace std;
char str[220]; //保存表达式字符串
int mat[][5] = { //优先级矩阵,若mat[i][j] == 1 ,则表示i号运算符优先级大于j号运算符,运算符编码规则为 + 为1号, - 为2号, *为3号, / 为4号,我们人为添加在表达式首尾的标记运算符为0号
	1,0,0,0,0,
	1,0,0,0,0,
	1,0,0,0,0,
	1,1,1,0,0,
	1,1,1,0,0,
};
stack<int> op; //运算符栈,保存运算符编号
stack<double> in; //数字栈,运算结果可能存在浮点数,所以保存元素为double
void getOp(bool & reto, int & retn, int & i) { //获得表达式中下一个元素函数,若函数运行结束时, 引用变量reto为true, 则表示该元素为一个运算符, 其编号保存在引用变量retn中;否则,表示该元素为一个数字,其值保存在引用变量retn中.引用变量i表示遍历到的字符串下标
		if (i == 0 && op.empty() == true) { //若此时遍历字符串第一个字符,且运算符栈为空, 我们人为添加编号为0的标记字符
				reto = true; //为运算符
			retn = 0; //编号为0
			return; //返回
		}
	if (str[i] == 0) { //若此时遍历字符为空字符,则表示字符串已经被遍历完
		reto = true; //返回为运算符
		retn = 0; //编号为0的标记字符
		return; //返回
	}
	if (str[i] >= '0' && str[i] <= '9') { //若当前字符为数字
		reto = false; //返回为数字
	}
	else { //否则
		reto = true; //返回为运算符
		if (str[i] == '+') { //加号返回1
			retn = 1;
		}
		else if (str[i] == '-') { //减号返回2
			retn = 2;
		}
		else if (str[i] == '*') { //乘号返回3
			retn = 3;
		}
		else if (str[i] == '/') { //除号返回4
			retn = 4;
		}
		i += 2; //i递增,跳过该运算字符和该运算字符后的空格
		return; //返回
	}
	retn = 0; //返回结果为数字
	for (; str[i] != ' ' && str[i] != 0; i++) { //若字符串未被遍历完,且下一个字符不是空格, 则依次遍历其后数字, 计算当前连续数字字符表示的数值
			retn *= 10;
		retn += str[i] - '0';
	} //计算该数字的数字值
	if (str[i] == ' ') //若其后字符为空格,则表示字符串未被遍历完
		i++; //i递增.跳过该空格
	return;//返回
}
int main() {
	while (gets(str)) { //输入字符串,当其位于文件尾时,gets返回0
		if (str[0] == '0' && str[1] == 0) break; //若输入只有一个0,则退出
		bool retop; int retnum; //定义函数所需的引用变量
		int idx = 0; //定义遍历到的字符串下标,初始值为0
		while (!op.empty()) op.pop();
		while (!in.empty()) in.pop(); //清空数字栈,和运算符栈
		while (true) { //循环遍历表达式字符串
			getOp(retop, retnum, idx); //获取表达式中下一个元素
			if (retop == false) { //若该元素为数字
				in.push((double)retnum); //将其压入数字栈中
			}
			else { //否则
				double tmp;
				if (op.empty() == true || mat[retnum][op.top()] == 1) {
					op.push(retnum);
				}//若运算符堆栈为空或者当前遍历到的运算符优先级大于栈顶运算符,将该运算符压入运算符堆栈
				else { //否则
					while (mat[retnum][op.top()] == 0) { //只要当前运算符优先级小于栈顶元素运算符, 则重复循环
							int ret = op.top(); //保存栈顶运算符
						op.pop(); //弹出
						double b = in.top();
						in.pop();
						double a = in.top();
						in.pop(); //从数字堆栈栈顶弹出两个数字,依次保存在遍历a.b中
						if (ret == 1) tmp = a + b;
						else if (ret == 2) tmp = a - b;
						else if (ret == 3) tmp = a * b;
						else tmp = a / b; //按照运算符类型完成运算
						in.push(tmp); //将结果压回数字堆栈
					}
					op.push(retnum); //将当前运算符压入运算符堆栈
				}
			}
			if (op.size() == 2 && op.top() == 0) break; //若运算符堆栈只有两个元素, 且其栈顶元素为标记运算符, 则表示表达式求值结束
		}
		printf("%.2f\n", in.top()); //输出数字栈中唯一的数字,即为答案
	}
	return 0;
}
  • 注意点

①记住四则远算 mat矩阵的用法,记住这个思路!!

②合并数字的写法:(char转int:a=str[i]-'0';)

retn = 0;
	for (;str[i] != ' '&&str[i] != 0;i++) {//合并数字
		retn *= 10;
		retn += str[i] - '0';
	}

③碰到中间有空格的输入,要记住整行读入:

//1 字符串String类
 #include <string>
        string a;
        getline(cin,a);

//2 char类 way①
 #include <cstdio>
         char[10] a;
         gets(a);//有些编译器such as Vs2015,要用gets_s()

//3 char类 way②
 #include <iostream>
         char[10] a;
         cin.getline(a,10);
        //cin.get(a,10);

判断字符数组最后的'\0':str[i]==0;

⑤循环输入,每次运算前清空栈是个好习惯!

⑥关于保留两位小数:

//1
float sp = 36.51647;
 sp=( (float)( (int)( (sp+0.005)*100 ) ) )/100;

//2
printf("%.2f",s);

⑦科普下:字符数组转int(可以用str+i 但是只能进行到空格为止!!)

int main(){
  char a[10]="123";
  int n;
  sscanf(a,"%d",&n);
  printf("%d",n);
  return 0;
}

⑧这道题的思路还是很好的,记得背下来~~

猜你喜欢

转载自blog.csdn.net/weixin_40614231/article/details/88366178