zoukankan      html  css  js  c++  java
  • 逆波兰式实现四则运算表达式计算器支持括号、十六进制

       最近做一个题目,要求实现简单的四则运算、支持括号和十六进制、浮点数等。同时能够进行输入合法检查。

          用逆波兰式(后缀表达式)实现时主要包括以下几个主要部分:

                  栈操作:包括入栈、出栈、是否为空、栈顶元素等,由于在栈操作中需要char型和float型,需要创建模板。

                  输入合法检查:包括输入合法字符、输入括号匹配、输入括号匹配、输入正确的十六进制、运算符无或连续。

                  提取输入表达式:由于输入的表达式中有浮点数或者十六进制数需要提取出来。

                  中缀表达式转化为后缀表达式:输入的表达式为中缀表达如a+b*c+(d*e+f)*g,需要将该表达式转化为后缀表达式即abc*+de*f+g*+。

                   计算后缀表达式:从而得到计算结果

                   计算结果输出处理:包括判断是否为有十六进制,对含有十六进制表达式的输出结果需要分析是否需要输出十六进制、输出结果是否为整数等

    分别分析如下:

            由于输入的表达式中有数字、字符等,在后来的栈操作时需要的不仅是char型的,还需要float型(int型数字也可以用float处理)。所以栈操作如下:定义栈模板。并实现具体操作:

    //自定义一个栈模板
    template <class T>
    class stack
    {
    public:
    	stack(){top = -1;}
    	T topElem();
    	T pop();
    	bool isEmpty();
    	void push(T _elem);
    private:
    	T elem[g_iconstArrayMax];
    	int top;
    };
    
    //入栈
    template <class T>
    void stack<T>::push(T _elem)
    {
    	if (top == g_iconstArrayMax - 1)
    	{
    		printf("栈满!
    ");
    	}
    	else
    	{
    		top++;
    		elem[top] = _elem;
    	}
    }
    
    //出栈
    template <class T>
    T stack<T>::pop()
    {
    	if (top == -1)
    	{
    		printf("栈空!
    ");
    		return 0;
    	}
    	else
    	{
     		T x = elem[top--];
     		return x;
    	}
    }
    
    //返回栈顶元素
    template <class T>
    T stack<T>::topElem()
    {
    	if (top == -1)
    	{
    		printf("栈空!
    ");
    		return 0;
    	}
    	else
    	{
    		return elem[top];
    	}
    }
    
    //是否为空
    template <class T>
    bool stack<T>::isEmpty()
    {
    	if (top == -1)
    	{
    		return true;
    	}
    	else
    	{
    		return false;
    	}
    }
    

    在对输入的表达式进行分析,由于输入的表达式中有可能哟float、十六进制,整数,于是需要对输入的表达式进行分析,将操作数和操作符分别提取出来。并在提取的同时将char型型计算出float int和十六进制数字,并将十六进制数字转化为int方便后来的计算。

    该功能由函数实现如下,在该函数中分别将数字存储在figure中,并将操作数用figure中的下标+1代替,结合操作符将,原表达式如1.23+0x23*2+(1.5*3-0.5)*2转化为仅包含int型下标和操作符如1+2*3+(4*5-6)*7的存储于dest中:

    //把数字都拆出来,然后放进figure数组中,将原字符串复制到dest中,
    //同时,数字全部用figure中对应的小标代替
    void cToFig(char* dest,char* str,float* figure)
    {
    	if (NULL == str)
    	{
    		printf("字符串为空!
    ");
    	}
    	else
    	{
    		int j = 0;
    		int figNum= 0;//figure下标
    		int powNum = 1;//pow的次数
    		int destNum = 0;//dest的下标
    		int i = 0;
    
    		while(str[i]!='')
    		{
    			if (str[i] >= '0' && str[i] <= '9')
    			{
    				j = i+1;
    				int inte = 0;//整数
    				float fnum = 0.0;//浮点数
    
    				if (str[j] == 'x')//出现十六进制
    				{
    					j++;
    					while ((str[j]!= NULL)&&(!isOperator(str[j])))
    					{
    						j++;
    					}
    					//计算出十六进制
    					for (int k = i+2; k < j; k++)
    					{
    						if (str[k] >= '0' && str[k] <= '9')
    						{
    							inte = inte*16+(str[k]-'0');//这里要区分是不是0-9 a-f
    						}
    						else
    						{
    							inte = inte*16+(str[k]-87);
    						}	
    					}
    					figure[figNum] = inte;
    					dest[destNum] = figNum + '1';
    					destNum++;
    					figNum++;
    					i= j;
    				}
    				else
    				{
    					while(str[j]>='0' && str[j] <= '9')
    					{
    						j++;
    					}
    					j--;
    
    					for (int k = i; k <= j; k++)
    					{
    						inte = inte*10+str[k]-'0';
    					}
    					j++;
    
    					if (str[j] == '.')
    					{
    						powNum = 1;
    						i = j+1;
    						j = j+1;
    						while(str[j]>='0' && str[j] <= '9')
    						{
    							j++;
    						}
    						for (int k = i; k < j; k++)
    						{
    							float tempf = pow(0.1,powNum);
    							powNum++;
    							fnum=fnum+tempf*(str[k]-'0');
    						}
    						i = j;
    						figure[figNum] = inte+fnum;
    						dest[destNum] = figNum + '1';
    						destNum++;
    						figNum++;
    					}
    					else
    					{
    						i = j;
    						figure[figNum] = inte;
    						dest[destNum] = figNum + '1';
    						destNum++;
    						figNum++;
    					}
    				}
    			}
    			else 
    			{
    				dest[destNum] = str[i];
    				i++;
    				destNum++;
    			}
    		}
    		dest[destNum] = '';
    	}
    }


    然后是将转化后的仅包含int型的中缀表达式转化为后缀表达式。中缀表达式转化为后缀表达式需要借助栈,当遇到操作数时放入数组压入栈,当遇到操作符时与栈顶元素进行比较,如果优先级低于栈顶元素则依次弹出,否则入栈,当遇到‘(’,直接压栈,但是遇到‘)',将栈内元素依次弹入到数组中直到遇到‘(’,具体实现如下:

    void midToback(char* backStr, char* midStr,int& m)
    {
    	if (NULL == midStr)
    	{
    		printf("表达式为空!
    ");
    	}
    	else
    	{
    		stack<char> oper;
    		//initStack(oper);
    		int len = strlen(midStr);
    
    		//char operOfMid = '';
    
    		for (int i = 0; i < len; i++)
    		{
    			//遇见表示操作数的数组下标
    			if (midStr[i] >= '1')
    			{
    				backStr[m] = midStr[i];
    				m++;
    			}
    			else if (midStr[i] == '(')
    			{
    				oper.push(midStr[i]);
    			}
    			else if (midStr[i] == '+')
    			{
    				//operOfMid = oper.top();
    				while (!oper.isEmpty()&&((oper.topElem()=='-') ||(oper.topElem()=='*')||(oper.topElem()=='/')||(oper.topElem()=='+')))
    				{
    					backStr[m++] = oper.topElem();
    					oper.pop();
    				}
    				oper.push(midStr[i]);
    			}
    			else if (midStr[i] == '-')
    			{
    				while (!oper.isEmpty()&&((oper.topElem()=='-') ||(oper.topElem()=='*')||(oper.topElem()=='/')))
    				{
    					backStr[m++] = oper.topElem();
    					oper.pop();
    				}
    				oper.push(midStr[i]);
    			}
    			else if ((midStr[i] == '*')||(midStr[i] == '/'))
    			{
    				oper.push(midStr[i]);
    			}
    			else if (midStr[i] == ')')
    			{
    				while(oper.topElem()!= '(')
    				{
    					backStr[m++] = oper.topElem();
    					oper.pop();
    				}
    				oper.pop();
    			}
    		}
    		while(!oper.isEmpty())
    		{
    			backStr[m++] = oper.topElem();
    			oper.pop();
    		}
    		backStr[m] = '';
    	}
    }
    

    在得到后缀表达式后,对表达式进行计算,如后缀表达式为123*+45*6-7*+,同样借助栈操作,当遇到操作数时压入栈,遇到操作符则依次弹出两个栈顶元素计算(需要注意:一、计算顺序,二、压入的是下标,计算时需要将对应的操作数提取出来计算)后压入栈,实现如下:

    float calcu(char* backStr,int m, float* fig)
    {
    	stack<float> sResult;//定义float栈放计算结果
    
    	float a,b,c,result = 0.0;
    
    	for (int i = 0; i< m;i++)
    	{
    		if (backStr[i]>='1')
    		{
    			//将数字对应到float中的数字,并放入栈
    			int tempSubscript = backStr[i]-'1';
    			sResult.push(fig[tempSubscript]);
    		}
    		else if(backStr[i] == '-')
    		{
    			a = sResult.pop();
    			b = sResult.pop();
    			c = b-a;
    			sResult.push(c);
    		}
    		else if (backStr[i] == '+')
    		{
    			a = sResult.pop();
    			b = sResult.pop();
    			c = b+a;
    			sResult.push(c);
    		}
    		else if (backStr[i] == '*')
    		{
    			a = sResult.pop();
    			b = sResult.pop();
    			c = b*a;
    			sResult.push(c);
    		}
    		else if (backStr[i] == '/')
    		{
    			a = sResult.pop();
    			b = sResult.pop();
    			c = b/a;
    			sResult.push(c);
    		}
    	}
    	result = sResult.pop();
    	return result;
    }


    计算结果出来之后,需要对计算结果进行分析:首先表达式中是否有十六进制,如果有十六进制且结果为整数则需要转化为十六进制输出,否则就按照i整数或者小数输出,所以这里还需要进行判断是否为整数,和十进制转化为十六进制。

    void tenToSixteen(char* sixteen,int n)
    {
    	int shang = 0;
    	int yushu = 0;
    	int value = 1;
    	int i = 0;
    	while(value <= n)
    	{
    		value = value*16;
    		yushu = n % value;
    		shang = yushu * 16 /value;
    
    		if (shang >=0 && shang <=9)
    		{
    			sixteen[i] = (char)(shang+48);
    		}
    		else
    		{
    			sixteen[i] =(char)(shang+87);
    		}
    		i++;
    	}
    	char str[g_iconstArrayMax] = "0x";
    	strrev(sixteen);
    	strcat(str,sixteen);
    	strcpy(sixteen,str);
    }
    
    //判断结果是不是int型
    bool isInte(float fresult)
    {
    	char fresultStr[g_iconstArrayMax];
    
    	sprintf(fresultStr,"%f",fresult);
    	
    	if (NULL == fresultStr)
    	{
    		return false;
    	}
    	else
    	{
    		int len = strlen(fresultStr);
    		int i = 0;
    		while (fresultStr[i]!='.')
    		{
    			i++;
    		}
    
    		if (fresultStr[i+1] == '0')
    		{
    			return true;
    		}
    		else
    		{
    			return false;
    		}
    	}
    }

    另外关于输入是否合法的检查,两个函数实现一个进行具体的判断,另一个判断括号是否匹配,同样利用栈操作实现:

    bool IsMatch(char* str)
    {
    	//初始化栈
    	stack<char> s;
    	//initStack(s);
    
    	int len = strlen(str);
    
    	char pp[g_iconstArrayMax];
    	char temp;
    	int k = 0;
    
    	for (int i= 0; i<len;i++)
    	{
    		switch(str[i])
    		{
    		case '(':
    			s.push(str[i]);
    			break;
    		case')':
    			{
    				temp = s.pop();
    				if (temp!='(')
    				{
    					return 0;
    				}
    				else
    				{
    					pp[k] = temp;
    					k++;
    				}
    				break;
    			}
    		default:
    			break;
    		}
    	}
    	pp[k] = '';
    
    	// 判断栈是否为空
    	if (s.isEmpty())
    	{
    		return true;
    	}
    	else
    	{
    		return false;
    	}
    }
    //检测是否合法
    bool isRightInput(char* str)
    {
    	//是否输入字符非法
    	if (NULL == str)
    	{
    		return false;
    	}
    	else
    	{
    		int len = strlen(str);
    
    		for (int i = 0; i<len; i++)
    		{
    			if (str[i]< '0')
    			{
    				if ((str[i] != '+')&&(str[i] != '-')&&(str[i] != '*')
    					&&(str[i] != '/')&&(str[i] != '.')&&(str[i] != '(')
    					&&(str[i] != ')'))
    				{
    					printf("输入非法字符!
    ");
    					return false;
    				}
    			}
    			else if ( str[i]> '9')
    			{
    				if ((str[i] < 'a'))
    				{
    					printf("输入非法字符!
    ");
    					return false;
    				}
    				else if ((str[i] > 'f')&&(str[i] != 'x'))
    				{
    					printf("输入非法字符!
    ");
    					return false;
    				}
    				else if(str[i] == 'x')
    				{
    					if (str[i-1] != '0')
    					{
    						printf("输入十六进制非法,请以0x开头!
    ");
    						return false;
    					}
    				}
    				else
    				{
    					if (str[i-1]!='x')
    					{
    						printf("输入非法字符!
    ");
    						return false;
    					}	
    				}
    			}
    		}
    		//检测括号匹配
    		if (!IsMatch(str))
    		{
    			printf("括号不匹配!
    ");
    			return false;
    		}
    		//检测是否出现连续的运算符或者没有运算法
    		int num = 0;
    		int k = 0;
    		for (int j = 0; j< len; j++)
    		{
    			if ((str[j] == '+')||(str[j] == '-')||(str[j] == '*')
    				||(str[j] == '/'))
    			{
    				num++;
    				k = j;
    				if ((str[k-1] == '+')||(str[k-1] == '-')||(str[k-1] == '*')
    					||(str[k-1] == '/')||(str[k+1] == '+')||(str[k+1] == '-')||(str[k+1] == '*')
    					||(str[k+1] == '/'))
    				{
    					printf("出现连续运算符!
    ");
    					return false;
    				}
    				else if ((str[j] == '/')&&(str[k+1] == '0'))
    				{
    					printf("被除数不能为0!
    ");
    					return false;
    				}
    				else if (str[k+1] == NULL)
    				{
    					printf("输入不完整!
    ");
    					return false;
    				}
    			}
    		}
    
    		if (num == 0)
    		{
    			printf("无运算符!
    ");
    			return false;
    		}
    		return true;
    	}
    }


    实现结果如下:

        

     

  • 相关阅读:
    P2403 [SDOI2010]所驼门王的宝藏
    差分约束系统
    题解报告——运输计划
    差分与树上差分
    题解报告——天使玩偶
    题解报告——Mokia
    CDQ分治&整体二分(未完待续)
    点分治
    AC自动机
    树链剖分
  • 原文地址:https://www.cnblogs.com/javawebsoa/p/3177772.html
Copyright © 2011-2022 走看看