栈—表达式求值、进制转换

github地址:https://github.com/Tory123/Algorithm-test/blob/master/Stack.cpp

//
//  main.cpp
//  Stack
//
//  Created by 杨涛睿 on 2020/7/27.
//  Copyright © 2020 杨涛睿. All rights reserved.
//

#include <iostream>
#include <stdio.h>
#include <math.h>
#include <string>

using namespace std;
//计算阶乘
int facI ( int n ) { int f = 1; while ( n > 1 ) f *= n--; return f; }
/*
  < : 栈顶运算符优先级更低,运算符进栈
  > : 栈顶运算符优先级更高,执行计算,结果入栈
 */
const char pri[9][9] ={
    
        // +   -   *   /   ^   !   (   )   \0
/*栈顶*/
/* + */   '>','>','<','<','<','<','<','>','>',
/* - */   '>','>','<','<','<','<','<','>','>',
/* * */   '>','>','>','>','<','<','<','>','>',
/* / */   '>','>','>','>','<','<','<','>','>',
/* ^ */   '>','>','>','>','>','<','<','>','>',
/* ! */   '>','>','>','>','>','>',' ','>','>',
/* ( */   '<','<','<','<','<','<','<','=',' ',
/* ) */   ' ',' ',' ',' ',' ',' ',' ',' ',' ',
/* \0 */  '<','<','<','<','<','<','<',' ','=',
};
char orderBetween(char a,char b){
    int c,d;
    
    switch (a) {
        case '+':c= 0;break;
        case '-':c= 1;break;
        case '*':c= 2;break;
        case '/':c= 3;break;
        case '^':c= 4;break;
        case '!':c= 5;break;
        case '(':c= 6;break;
        case ')':c= 7;break;
        case '\0':c= 8;break;
        default:break;
    }
    switch (b) {
        case '+':d= 0;break;
        case '-':d= 1;break;
        case '*':d= 2;break;
        case '/':d= 3;break;
        case '^':d= 4;break;
        case '!':d= 5;break;
        case '(':d= 6;break;
        case ')':d= 7;break;
        case '\0':d = 8;break;
        default: break;
    }
    return pri[c][d];
}
void append ( char*& rpn, float opnd ) { //将操作数接至RPN末尾
   int n = strlen ( rpn );
   if ( opnd != ( float ) ( int ) opnd )
       sprintf ( rpn+n, "%.2f \0", opnd ); //浮点格式
   else
       sprintf ( rpn+n, "%d \0", ( int ) opnd ); //整数格式
   // strcat ( rpn, buf ); //RPN加长
 }
void append ( char*& rpn, char optr ) { //将运算符接至RPN末尾
    int n = strlen ( rpn ); //RPN当前长度(以'\0'结尾,长度n + 1)
    sprintf ( rpn + n, "%c ", optr ); rpn[n + 2] = '\0'; //接入指定的运算符
 }
/*栈模板类
 栈的应用场合主要分为以下四类:
 (1)逆序输出:输出次序与处理过程颠倒——进制转换
 (2)递归嵌套——括号匹配
 (3)延迟缓冲,需要读取一定长度后,才能进行处理 ——中缀表达式求值
 (4)栈式计算
 */
template <typename T>
class Stack{
public:
    T stack[100];
    int size = 0;
    void push(T e){
        size<100?stack[size++]=e: NULL;
    }
    float pop(){
        
        return stack[--size];
    }
    //取顶
    T& top(){
        return stack[size-1];
    }
   
    //进制转换,base是十进制,num是转化的目标进制
    void convert(int base ,int n){
        while(base > 0){
            this->push(base%n);
            base/=n;
        }
        while(size>0){
            cout << this->pop();
        }
        cout << endl;
    }
    /*
     括号匹配
     无括号的表达式是匹配的
     减而治之:减少部分括号,不影响表达式的正确性
     分而治之:两个表达式E和F已经是括号匹配的,则串接起来可以得到一个匹配的表达式
     但是,
     ———— 串接起来匹配的表达式,两个子表达式原先未必匹配
     因此采用减而治之的策略
     ————减去一对紧邻的括号不影响原表达式匹配与否,遇到左括号入栈,遇到右括号出栈
     为什么使用栈而不是计数器?———— 栈可以判断多种括号并存的情况
     */
    bool parel(string s ,int lo,int hi){
        for(int i = 0; i<s.size() ;i++){
            if(s[i]=='(')this->push(s[i]);
            if(s[i]==')')this->pop();
        }
        if(this->size==0)return true;
        return false;
    }
    /*
        栈混洗——借助中转栈C,将栈A中的元素转入栈B
        栈B中的元素序列,可能与栈A不同
        长度为n的序列,可能的栈混洗总数为卡特兰数(2n)!/((n+1)!n!)
        判断一个序列是否满足栈混洗的充要条件 ——> 312情况
        甄别算法:暴力枚举——>O(n^3)
        O(n)复杂度算法 ——>模拟!
        n个括号匹配的本质,就是对n个元素进行栈混洗的一系列push和pop操作
    */
};
void readNumber ( char*& p, Stack<float>& stk ) { //将起始于p的子串解析为数值,并存入操作数栈
   stk.push ( ( float ) ( *p - '0' ) ); //当前数位对应的数值进栈
   while ( isdigit ( * ( ++p ) ) ) //只要后续还有紧邻的数字(即多位整数的情况),则
      stk.push ( stk.pop() * 10 + ( *p - '0' ) ); //弹出原操作数并追加新数位后,新数值重新入栈
   if ( '.' != *p ) return; //此后非小数点,则意味着当前操作数解析完成
   float fraction = 1; //否则,意味着还有小数部分
   while ( isdigit ( * ( ++p ) ) ) //逐位加入
   stk.push ( stk.pop() + ( *p - '0' ) * ( fraction /= 10 ) ); //小数部分
}
 //执行一元运算
float calcu ( char op, float b ) {
    switch ( op ) {
       case '!' : return ( float ) facI ( ( int ) b );
       default  : exit ( -1 );
    }
}
//执行二元运算
float calcu ( float a,char op, float b ) {
    switch ( op ) {
       case '+' : return  ( float ) ( a + b );
       case '-' : return  ( float ) ( a - b );
       case '*' : return  ( float ) ( a * b );
       case '/' : return  ( float ) ( a / b );
       case '^' : return  pow(a, b);
       default  : exit ( -1 );
    }
}
  /*
  中缀表达式求值,顺带完成中缀表达式向后缀表达式(RPN)的转换
  同样采用减而治之的策略,减少运算符数目,并不影响正确性
  采用两个栈——将运算符和运算数分别对待
  */
float evaulate(char*S,char* RPN){
    //操作数栈和运算符栈
    Stack<float>opnd; Stack<char>optr;
    optr.push('\0');
    while(optr.size!=0){
        if(isdigit(*S))
        {readNumber(S,opnd); append(RPN,opnd.top()); }
        else
            //比较当前运算符和栈顶元素优先级高低
            switch(orderBetween(optr.top(),*S) ){
                case '<':
                    optr.push(*S);S++;
                    break;
                case '=':
                    optr.pop();S++;
                    break;
                case '>':
                    char op = optr.pop();
                    append(RPN,op);
                    if(op=='!')opnd.push(calcu(op,opnd.pop()));
                    //除了阶乘都是二元运算符
                    else{
                        float pOpnd2 = opnd.pop(),pOpnd1 = opnd.pop();
                        opnd.push(calcu(pOpnd1,op,pOpnd2));
                    }
                    break;
            }
    }
    return opnd.pop();
}

int main(int argc, const char * argv[]) {
    char RPN[100];
    cout << evaulate("3+2",RPN)<<endl;
    cout << RPN;
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值