HTUT数据结构作业感悟和分析-----C++运用栈解决四则运算

//我只是HFUT的一个普通学生,希望把自己学习感悟更新上来
//今天已经周四,(吐舌头,张老师要求明天就交作业,确实有点晚了
//以后尽量做到周一更新一下
//原理方面我就不再赘述了,以后会说得清楚一点,下面附上我参考过的几个网页
// http://blog.csdn.net/summerxiachen/article/details/77073320
// http://blog.csdn.net/qq_34992845/article/details/70313588
//下面的代码能够实现带括号四则运算,并且处理了一位以上的整数
//感兴趣的同学,可以搜索一下前缀(波兰)、中缀和后缀(逆波兰)表达式
//另外二叉树也可以解决四则运算,稍后我会进行更新
//数据结构很难啃,大家加油
#include<iostream>
using namespace std;
//下面是我自己写的一个栈,相比于STL模板库的栈,pop()函数不仅可以删除栈顶元素,还可以将栈顶元素的值返回
template<class T>
class Stack{
 public:
  class Node{ //使用了链栈来实现,不懂链表的同学看一下课本,这里使用一个内部类表示每个节点
   public:
    T value;//用来存储当前节点的值
    Node* prev = NULL;//用来存储前一个数据的地址
  };
  int length = 0;//栈的大小,(此处我的devc++报了一个warning,不过我懒得管了)
  Node* tail = NULL;//用来记录栈顶元素的地址
  Node* p = NULL;//用来作为一个中间的存储变量,没有实际意义,读者可以自行体会
  void push(T val){//入栈操作
   p = new Node;//用new开一个新空间,并用p记录其地址
   p->value = val;//不用多说。将val的值存储
   p->prev = tail;//tail指向当前的栈顶元素,而p指向待更新的栈顶元素,所以p的前一个元素肯定是当前的栈顶元素啦
   tail = p;//前面说了,p只是一个中间的存储变量,所以最后还要更新tail的值,更新tail为p
   length++;//栈的大小变大
  }
  int size(){//得到栈的大小
   return length;
  }
  T pop(){//返回当前栈顶元素,并删除
   T value = tail->value;//记录需要返回的value的值,不然一会就delete释放了
   p = tail;//用中间变量p存储tail
   tail = tail->prev;//将tail的地址更新为tail的前一个的地址
   delete p;//现在栈顶空间已经没有用处了,所以释放掉
   length--;//栈的大小变小
   return value;
  }
  T top(){//仅返回当前栈顶元素,但不删除
   return tail->value;
  }
  bool empty(){//判断当前栈是否为空
   return length == 0;
  }
};
//函数prototype写在前面,函数实现在主函数之后,前面进介绍功能,不明白的话,后面还有详细的解释
bool isNum(char);//判断一个字符是不是数字
   
bool comparison(char, char);//比较两个字符的大小(是按照优先级比较的),如果前一个字符大于等于后一个字符,为真
   
int translation(char);//这个函数是comparison的辅助函数,将'('表示为0 ,'+'和'-'均为1,'*'和'/'均为2
int operation(char, int, int);//这个是用来运算的,返回运算结果,第一个是运算符,后两个是运算数
int addition(int, int);//加法
 
int subtraction(int, int);//减法
 
int multiplication(int, int);//乘法
 
int division(int, int);//除法
int main(){
 Stack<int> s_num;//数字栈
 Stack<char> s_oper;//符号栈
 bool isnum = false;//用来存储当前字符的上一个字符是不是数字,以此来解决一位以上整数的问题
 //附上一个测试案例,答案算出来是3
 string str = "(9-3*2)-7*2/1-((2-3+1*4)-5)*(2*12+2)/4+1";  
 
    for(int i = 0; i < str.length(); i++) {//遍历字符串的每个字符
     if(isNum(str[i])) {//如果是数字
      if(isnum){//如果当前数字字符的上一个字符是数字,就出栈乘10移位再加上当前的数字字符的数值,然后再入栈
       s_num.push(s_num.pop() * 10 + (str[i] - '0'));
   }else{//上一个不是数字,就直接入栈了
    s_num.push(str[i] - '0');
    isnum = true;//别忘了修改isnum的值
   } 
     }else { //如果是符号          
   if(str[i] == ')'){//重点!!字符只分为两种,不可以入栈的(即')'),和可以入栈的(其他符号)
    while(s_oper.top() != '(') {//一直向前扫描,直到寻找到'('
//下面这个式子有点装逼,要注意到,两个pop()函数,是先算右边的,后算左边的额,这和编译原理有关系
//如果不明白,我将等价的式子写在下面
//int num1 = s_num.pop();  
//int num2 = s_num.pop();
//int result = operation(s_oper.pop(), num2, num1);
//s_num.push(result);
     s_num.push(operation(s_oper.pop(), s_num.pop(), s_num.pop()));
       }
       s_oper.pop();//别忘了删除'('
   }else{//可以入栈的,又分为可以直接入栈的,和需要进行一些操作再入栈的
//但无论如何,可不可以直接入栈,最后都要入栈,所以在if之后有一个入栈语句
//可以直接的入栈的,有三种情况
//1. 当前栈空 2.当前符号为'(' 3.当前符号的优先级大于栈顶符号(这也是为什么'('优先级定为0,避免出现意外出栈的情况)
    if(!s_oper.empty() && str[i] != '(' && !comparison(str[i], s_oper.top())){//过滤掉以上三种情况
     while(!s_oper.empty() && !comparison(str[i], s_oper.top())){
//栈不能空,不然怎么比较;当当前符号优先级大于栈顶的符号时,就要停止
      s_num.push(operation(s_oper.pop(), s_num.pop(), s_num.pop()));//原理同上
     }
    }
    s_oper.push(str[i]);
   }
   isnum = false;//别忘了修改isnum的值
     }
    }
  
    while(!s_oper.empty()) {//如果遍历完了,符号栈还有元素,那么就需要出栈全部运算了才可以
  s_num.push(operation(s_oper.pop(), s_num.pop(), s_num.pop()));
    }
    cout << s_num.pop();//输出结果
   
    return 0;
}
    
bool isNum(char char_0) {//判断一个字符是不是数字
    if(char_0 >= '0' && char_0 <= '9') {
     return true;
    }
    return false;

bool comparison(char char_1, char char_2) {//比较函数
    if(translation(char_1) > translation(char_2)) {
     return true;
    }
    return false;
}
 
int translation(char char_0) {//翻译函数,将符号用数字表示
    switch(char_0) {
     case '(':
   return 0;
   
     case '+':
      return 1;
        
     case '-':
      return 1;
      
     case '*':
      return 2;
      
     case '/':
      return 2;
  
     default:
      return 0;
    }
}
int operation(char oper, int num_1, int num_2){//运算函数,分为四个子函数
    switch(oper){
     case '+':
      return addition(num_1, num_2);
     
     case '-':
      return subtraction(num_1, num_2);
      
     case '*':
      return multiplication(num_1, num_2);
      
     case '/':
      return division(num_1, num_2);
         
     default:
      return 0;
 }
}
int addition(int num_1, int num_2){
 return num_1 + num_2;
}
 
int subtraction(int num_1, int num_2){
 return num_1 - num_2;
}
 
int multiplication(int num_1, int num_2){
 return num_1 * num_2;
}
 
int division(int num_1, int num_2){
 return num_1 / num_2;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值