• 表达式求值的另一种方法


    表达式求值除了用文法实现之外,还可以直接用栈,将中缀表达式转化为后缀表达式。然后再用求表达式的值就轻而易举了。

    下面贴程序源码:(可能有点长,呵呵:)

    main.cpp

    #include"stack.cpp"
    #include"stack.h"
    #include<iostream>
    using namespace std;
    /*
    *  该函数有两个功能
    *  1. 输入中缀表达式
    *  2. 将中缀表达式转化为后缀表达式
    *  形参为两个指针分别指向两个数组(一个储存数字,一个储存运算符)
    *  返回值是数字和运算符的总个数(若转化出错,返回-1)
    */
    int change(double *Darra,char *Carra)
    {
        int num = 0;									//记录式子中数字和运算符总数
    	char ch;										//暂时存储,输入字符 
        double dou;										//暂时存储,输入数字 
    	Stack<char>   mychar;							//存储运算符
    	bool wchar = false;                             //是否有非法字符
    	cout<<"请输入表达式(为了方便可以带空格),并以'='号结束:\n"<<endl;
    	while( cin>>ch, '='!=ch )
    	{
    		switch(ch)
    		{
    		case '0':            case '5':
    		case '1':            case '6':
    		case '2':            case '7':
    		case '3':            case '8':
    		case '4':            case '9':
    				num++;
    				cin.putback(ch);					//如果是数字,扔回去,用double型数据装
    				cin>>dou;
    				cout<<dou<<ends;                    //后缀表达式部分输出
    			    Darra[num] = dou;
    		        break;
    		case '+':
    		case '-':
    		case '*':
    		case '/':
                    while(  (!mychar.Isempty()) &&      //栈非空
    					    (mychar.Top()!='(') &&      //栈顶元素不是空括号
    						( (mychar.Top()=='*') || (mychar.Top()=='/') || (ch == '+') || (ch == '-') )  )
    					                                //栈顶运算符优先级不低于输入的运算符
    													//满足以上三个条件,将栈中元素全部弹出
    				{
    					num++;
    					cout<<mychar.Top()<<ends;		//后缀表达式部分输出
    					Carra[num] = mychar.Top();
    					mychar.Pop();
    				}
    				mychar.Push(ch);					//若不满足,则将出入运算符压入栈中
    			    break;
    		case '(':
    			    /*
    				*   尝试解决省略*的运算不成功
    			    if('\0' == Carra[num] && num != 0)
    				{
    					num++;
    					cout<<'*'<<ends;
    					Carra[num] = '*';
    				}
    				*/
    			    mychar.Push('(');					//遇到开括号压入栈
                    break;
    		case ')':									
    			    if(mychar.Isempty())				//判断括号是否匹配
    				{
    					cout<<"\n\n有多余的')'..."<<endl;
    					return -1;
    				}
    				while(!mychar.Isempty())			//遇到闭括号,将栈中元素弹出
    				{
    					if('(' == mychar.Top())			//直至遇到开括号
    					{
    						mychar.Pop();
    						break;
    					}
    					else							//如果栈为空,任然没有开括号,则执行弹出操作时,会出现错误,退出系统
    					{
    						num++;
    						cout<<mychar.Top()<<ends;	//后缀表达式部分输出
    						Carra[num] = mychar.Top();
    						mychar.Pop();
    					}
    				}
                    break;
    		case ' ':
    			    break;
    		default:                                    //检测非法字符
    			    wchar = true;
    		}
    
    	}
    	 while(!mychar.Isempty())						//将栈中剩余运算符输出
    		{
    		    if('(' == mychar.Top())                 //括号不匹配
    			{
    				cout<<"\n\n有多余的'('..."<<endl;
    				return -1;
    			}
    		    num++;
    			cout<<mychar.Top()<<ends;				//后缀表达式部分输出
    			Carra[num] = mychar.Top();
    			mychar.Pop();
    		}
    	    if(0 == num)                                //没有任何表达式输入                      
    		{
    			cout<<"\n\n您没有输入任何表达式..."<<endl;
    		    return -1;
    		}
    	if(wchar)                                      
    	{
    		cout<<"(字串中有非法字符)";
    	}
    	 cout<<endl<<"\n以上为中缀表达式和相应的后缀表达式,";
    	return num;
    }
    
    /*
    *  运算函数,将储存在数组中的符号和数字(后缀表达式)取出,计算成结果返回
    *  形参:   储存有后缀表达式的两个数组首地址(此处若用栈,则后缀表达式从栈中输出时,其顺序完全反相),后缀表达式的长度
    *  返回值: 后缀表达式的计算结果
    */
    double Compute(char *Carra,double *Darra, int num)
    {
    	int i = 1;										//取后缀表达式的辅助变量
    	double d1,d2;									//暂存栈中弹出的两个变量
    	Stack<double> Res;								//运算栈,储存数字
    	while( i <= num )								
    	{
    	    if(Carra[i] == '\0')						//如果i处是无效运算符,说明后缀表达式中,i处对应的应该是数字
    		{
    				Res.Push(Darra[i]);					//数字入栈
    		}
    		else                                        //如果是运算符
    		{
    			   d1 = Res.Top();  
    			   Res.Pop();
    			   d2 = Res.Top();   
    			   Res.Pop();							//从栈顶弹出两个数据进行计算  
    			   switch(Carra[i])
    			   {
    			   case '+':
                       Res.Push(d1+d2);					//计算后压回栈
    				   break;
    			   case '-':
    				   Res.Push(d2-d1);
    				   break;
    			   case '*':
    				   Res.Push(d1*d2);
    				   break;
    			   case '/':
    				   if(0 == d1)
    				   {
    					   cout<<"请注意分母不能为零..."<<endl;
    					   system("pause");
    					   exit(0);
    				   }
    				   Res.Push(d2/d1);
    				   break;
    			   default:
    				   cout<<"(Compute)运算符匹配出错了..."<<endl;
    				   exit(0);
    			   }
    		}
            i++;
    	}
    	return Res.Top();								//弹出栈中最后一个数字(计算结果)
    }
    
    
    int main()
    {
    	int i;
    	double Darra[S_size];							//装入数据
    	char Carra[S_size];								//装入运算符
    	for(i=0; i<S_size; i++)							//将储存运算符的数组做一个标记,以明确该下标所对应的是数字还是运算符
    		Carra[i] = '\0';                            //若检测到Carra[i] = '\0',则说明Carra[i]中没有存入运算符,而Darra[i]中存储了一个数字
    
    	cout<<"*************************  一个简单表达式计算程序 *************************"<<endl;
    	cout<<"                                                                  ——by HQ"<<endl;
    	cout<<"注意:请写全表达式,不要省略'*',写负数时请写成 '0 - x'的形式.\n"<<endl;
    
    	if( ( i = change(Darra,Carra) )== -1 )			//判断转换是否成功
    	{
           cout<<"\n转换失败..."<<endl;
    	   system("pause");
    	   exit(0);
    	}
    	else
    	{
    		 cout<<"其计算结果为:\n"<<endl;
    		 cout<<Compute(Carra,Darra,i)<<endl;		//计算并输出结果
    	}
    	system("pause");
    	return 0;
    }

    stack.cpp

    /*
    *    模板类(栈)的实现
    */
    #ifndef Stack_cpp
    #define Stack_cpp
    
    #include"Stack.h"
    
    template<class T>
    Stack<T>::Stack()
    {
        top = -1;
    }
    
    template<class T>
    bool Stack<T>::Isempty()       // If the stack is empty, return true; otherwise return false.
    {
    	if(-1 == top)
    	{
    		return true;
    	}
    	else
    	{
    		return false;
    	}
    }
    
    template<class T>
    void Stack<T>::Pop()           // Pop an element from the top of the stack 
    {
    	if(top == -1)
    	{
    		cout<<"弹出栈出错..."<<endl;
         	exit(0);
    	}
    	top--;
    }
    
    template<class T>
    void Stack<T>::Push(T ele)     // Push this element into the stack.
    {
    	if(top > S_size)
    	{
    		cout<<"栈溢出..."<<endl;
    		exit(0);
    	}
    	top++;
        elem[top] = ele;
    }
    
    template<class T>
    T Stack<T>::Top()              // Return the top element of the stack.
    {
    	if(-1 == top)
    	{
           cout<<"已至栈底..."<<endl;
    	   //exit(0);
    	}
    	return elem[top];
    }
    
    template<class T>
    int Stack<T>::Size()           //Return the number of the elements in the stack.
    {
    	return top;
    }
    
    template<class T>              // clear all the elements in the stack
    void Stack<T>::clear()
    {
    	top = -1;
    }
    #endif


    stack.h

    /*
    *    模板类(栈)
    */
    
    #ifndef Stack_h
    #define Stack_h
    
    #define S_size  50                         //the size of the stack
    
    template<class T>
    class Stack
    {
    public:
    	Stack();
       	void Pop();                            // Pop an element from the top of the stack 
     	void Push(T elem);                     // Push this element into the stack.
     	T Top();                               // Return the top element of the stack.
     	bool Isempty();                        // If the stack is empty, return true; otherwise return false.
     	int Size();                            // Return the number of the elements in the stack.
    	void clear();                          // clear all the elements in the stack
    private:
        T elem[S_size];
    	int top;
    };
    
    #endif
    


    运行结果:



  • 相关阅读:
    zipkin启动报错(Caused by: java.lang.ClassNotFoundException: zipkin.Component)的解决方法
    Java中的long与double的区别
    redis使用笔记
    解决node编程频繁修改代码,需要重启服务器问题
    远程连接mysql要点 虚拟主机定义与分类
    详析静态网站与动态网站区别(服务器ip dns 端口)
    JavaEE-实验四 HTML与JSP基础编程
    JavaEE-实验三 Java数据库高级编程
    JavaEE-实验二 Java集合框架实验
    mysql中文乱码 常见编码问题解决方法分享
  • 原文地址:https://www.cnblogs.com/xinyuyuanm/p/2979594.html
Copyright © 2020-2023  润新知