C++抽象编程——STL(2)——括号匹配与口袋计算器

今天我抽时间看了看栈的题目,写了个自以为很直观的C++代码,实话,按照我们抽象书上的编程思路,整个过程就像是有人在前面引路一样,而且我发现我的代码也规范了很多。
好,这次我先来整理笔记。上次太晚没来得及写分析,这次补上:
首先括号匹配问题是我们数据结构书上的题目,留给我们作为习题的p49,比如输入({[][]}),这样就是正确的,但是[(]就是错误的。书上的方法解释的有点啰嗦,我就按照自己的想法说了:
利用栈的原理,我们可以这样,我们知道左边的括号一定与右边的相匹配,所以我们建立一个char类型的栈,用于存放六中括号类型。其次如果放入的是左括号,那么就压入栈堆中,一旦放入的是右括号,那么就与栈顶的左括号作为比较,一旦匹配,就将左括号去除,继续下一轮的比较,如果不匹配,那么直接返回“NO”.
从下面的代码我们可以看到下面的一些函数:

  • bool isLeftBrackets(char ch); 用来判断压入栈的是不是左括号
  • bool isBracket(char ch); 用来判断用户输入是否为括号类型(在用户的角度思考用户可能的输入)
  • bool isMatchingBracket(char lb, char rb); 用来判断两个括号是不是匹配,lb代表左括号,rb代表右括号。
  • int removeBrackets(stack< char > & operandStack, char ch); 执行移除匹配括号的操作

/*括号匹配*/
#include <iostream>
#include <string>
#include <stack>
 using namespace std;
/*funtion prototypes */
 bool isLeftBrackets(char ch);
 bool isBracket(char ch);
 bool isMatchingBracket(char lb, char rb);
 int removeBrackets(stack<char> & operandStack, char ch);
 /*main funtion */
 int main() {
    while(true) {
    cout << "please input brackets" << endl;
    stack<char> operandStack;
    string brackets;
    getline(cin,brackets);
    if (brackets.length() == 0) { cout << "error,please input brackets" << endl; }
    for (int i = 0; i < brackets.length(); i++) {
        char ch = brackets[i];
        if (!isBracket(ch)) {
            cout << "input error" << endl;
            break;
        } else if (isLeftBrackets(ch)) {
            operandStack.push(ch);
        } else {
            removeBrackets(operandStack,ch);
        }
    }

    if (operandStack.empty()) {
        cout << "Yes" << endl; 
        } else {
            cout << "NO" << endl;
        }
    }
      return 0;
 } 
 /* 检查输入的是否为括号 */
bool isBracket(char ch) {
    if (isLeftBrackets(ch)) return true;
    switch (ch) {
        case ')': case ']': case '}':
            return true;
            default:
                return false;
    }
}
/*判断是否为左括号 */
bool isLeftBrackets(char ch) {
    switch (ch) {
        case '(': case '{': case '[':
            return true;
            default:
                return false;
            }
}
/*从栈中移除括号 */
int removeBrackets(stack<char> & operandStack, char ch) {
    if(operandStack.empty()){
    return 0;
    } else {
    if(isMatchingBracket(operandStack.top(), ch)) {
        operandStack.pop();
    } else {
        return 0;
    }
}
}
bool isMatchingBracket(char lb, char rb) {
    if ((lb == '(' && rb == ')' ) || ( lb == '[' && rb == ']') || (lb == '{'
     && rb == '}')) {
    return true;
    } else {
        return false;
    }
}

实例如下:
这里写图片描述

这里写图片描述
这里写图片描述
这里写图片描述

口袋计算器

这个问题是抽象编程书上面的一个经典问题,堆栈的一个有趣的应用是在电子计算器中用以存储计算的中间结果,这个作用在早期科学中最容易看到。在早期被称为reverse Polish notation。简称为RPN.
在RPN当中,操作符常常在操作数的输入之后,比如下面的表达式:
8.5 * 4.4 + 6.9 / 1.5
在RPN中你是这样输入的:
RPN
enter代表输入。当你按下ENTER键时,计算机就会将先前的数压入栈中。当你输入的是运算符的时候,计算机就会检查你刚刚输入的是不是数字,如果是,那么就将它取出来,然后进行计算。因此我们可以看出来,它计算的过程就想这样

  • 从栈顶中取出两个元素(Popping the top two values from the stack)
  • 将你输入的运算符应用于两个数值中(Applying the arithmetic operation indicated by the button to these values)
  • 把结果压回栈中(Pushing the result back on the stack)

事实上,每次用户输入一个数据,都会放在栈顶,也就是说我们看到的元素总是栈顶的元素。下面的图片说明了RPN的运行范式:
RPN运行过程

下面的代码就展示了这样一个计算器,当然我们需要思考它具备什么样的功能:

  • A floating-point number(我们的操作数为浮点数)
  • An arithmetic operator chosen from the set +, -, *, and / (我们可以从这四个操作符中选取操作)
  • The letter Q, which causes the program to quit(按下q或Q,退出)
  • The letter H, which prints a help message(按下h或者H,获得帮助菜单)
  • The letter C, which clears any values left on the stack (按下c或者C,清空栈)

我写的代码如下:

/*口袋计算器 */
#include <iostream>
#include <string>
#include <cctype>
#include <stack>
#include <cstdlib>
using namespace std;
/*函数原型*/
void applyOperator(char op,stack<double> & operandStack);
void helpCommand();
void error(string msg);
void clearOperandStack(stack<double> & operandStack);
/*主函数*/
int main () {
    cout << "RPN Calculator Simulation (type H for help)" << endl;
    stack<double> operandStack;
    while(true) {
        cout << ">";
        string line;
        getline(cin,line);
        if (line.length() == 0) {
        line = "Q";
    }
        char ch = toupper(line[0]);
        if (ch == 'Q') {
            break;
        } else if (ch == 'H') {
            helpCommand();
        } else if (ch == 'C') {
            clearOperandStack(operandStack);
        } else if (isdigit(ch)) {
            operandStack.push(atof(line.c_str()));
        } else {
            applyOperator(ch,operandStack);
        }
    } 
    return 0;
} 

void error(string msg) {
    cerr << msg << endl;
    exit(EXIT_FAILURE);
}
void applyOperator(char op, stack<double> & operandStack) {
    double result;
    double rhs = operandStack.top();
    operandStack.pop();
    double lhs = operandStack.top();
    operandStack.pop();
    switch (op) {
    case '+': result = lhs + rhs; break;
    case '-': result = lhs - rhs; break;
    case '*': result = lhs * rhs; break;
    case '/': result = lhs / rhs; break;
    default: error("Illegal operator");
}
    cout << result << endl;
    operandStack.push(result);
}
void helpCommand() {
    cout << "Enter expressions in Reverse Polish Notation," << endl;
    cout << "in which operators follow the operands to which" << endl;
    cout << "they apply. Each line consists of a number, an" << endl;
    cout << "operator, or one of the following commands:" << endl;
    cout << " Q -- Quit the program" << endl;
    cout << " H -- Display this help message" << endl;
    cout << " C -- Clear the calculator stack" << endl;
}
void clearOperandStack(stack<double> & operandStack) {
    while (!operandStack.empty()) {
        operandStack.pop();
    }
}

书上的代码很多是他自己的接口,所以,我就改为了我们C++通用的。比如这一个atof(line.c_str() 就是先把字符串妆变为c类型的字符,然后转换为数字类型,字符串的加是连接,不是所谓的加法,所以要进行转换。这里用到了我上次说的一些我们自定义的代码,参考我上一篇的博文,C++抽象编程——STL(2)——stack类
话不多说,运行一下:
运行结果

PS:在写这个程序的时候,我犯了一个很低级的错误,那就是if (ch == ‘Q’) 我硬是写成了if (ch = ‘Q’),检查还没发现,跑去论坛发帖,实在丢人。有时候一些低级错误,犯了都很难找到。真的很谢谢那位指出我错误的同学,谢谢

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值