算例一
-
题目描述
-
解题思路
①括号匹配是典型的栈问题,要点是:遍历的每一个右括号都会和它左边最近的左括号相匹配
②遇到左括号,压入栈;遇到右括号,栈弹出
-
解题代码
#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;
}
⑧这道题的思路还是很好的,记得背下来~~