小程序(十六)简单四则运算

问题描述:
输入一个只包含个位数字的简单四则运算表达式字符串,计算该表达式的值
注:
3.1、表达式只含 +, -, *, / 四则运算符,不含括号
3.2、表达式数值只包含个位整数(0-9),且不会出现0作为除数的情况
3.3、要考虑加减乘除按通常四则运算规定的计算优先级
3.4、除法用整数除法,即仅保留除法运算结果的整数部分。比如8/3=2。输入表达式保证无0作为除数情况发生
3.5、输入字符串一定是符合题意合法的表达式,其中只包括数字字符和四则运算符字符,除此之外不含其它任何字符,不会出现计算溢出情况
要求实现函数:
int calculate(int len,char *expStr)
【输入】 int len: 字符串长度;char *expStr: 表达式字符串;
【输出】 无
【返回】 计算结果
示例:
1)输入:char *expStr = “1+4*5-8/3”
函数返回:19
2)输入:char *expStr = “8/3*3”

函数返回:6


第一种方法:利用后缀表达式:

#include<stdio.h>
#include<stdlib.h>
#include<stack>
using namespace std;


int calculate(int len,char *expStr)
{
  int i;
  int j=0;
  char * postfix = (char*)malloc(sizeof(char)*len);
  stack<char> oper;
  for(i=0;i<len;i++)//计算后缀表达式
  {
	if(expStr[i]>='0' && expStr[i]<='9')
	   postfix[j++] = expStr[i];
	else
		switch(expStr[i])
		{
		  case'+':
		  case'-':if(oper.empty())
				  { 
					oper.push(expStr[i]);
				    break;
				  }
				  while(!oper.empty() && oper.top()!='(')
				  {//如果是'+'或'-',就把栈顶及以以下的元素全部出栈到后缀表达式中,
                   //(按照当前元素优先级小于或等于栈顶元素,则将栈顶元素出栈的原则,
				   //如果栈顶元素是'(',则认为 '(' 优先级最小。因此将'+'或'-'压栈。
					  postfix[j++] = oper.top();
					  oper.pop();
				   }
			       oper.push(expStr[i]);
				   break;
          case'*':
		  case'/':if(oper.empty())
				  {
				    oper.push(expStr[i]);
					break;
				  }
			      if(oper.top()!='*'&&oper.top()!='/')
				      oper.push(expStr[i]);
				  else 
				    {
					  while(!oper.empty() && (oper.top()=='*' || oper.top()=='/'))
					  {
					      postfix[j++] = oper.top();
					      oper.pop();
					  }
					  oper.push(expStr[i]);
				    }
				  break;
		  case'(':oper.push(expStr[i]);break;//左括号在进栈前,认为优先级是最大的
		  case')':while(oper.top()!='(')
				  {//当前元素是右括号时,认为右括号的优先级最小,将栈中元素都出栈到
				   //后缀表达式中,直到遇到左括号,这时直接将左括号弹出(删除),而
				   //且右括号也不入栈(后缀表达式中是没有括号的)
				     postfix[j++] = oper.top();
					 oper.pop();  
				  }
				  oper.pop();
				  break;
		  default:exit(0);
	     }
  }
  while(!oper.empty())
  {
	  postfix[j++] = oper.top();
	  oper.pop();
  }
  postfix[j]='\0';
  //printf("%s\n",postfix);

  //利用后缀表达式求值
  //每当遇到一个操作符是,就将它的前两个数弹出
  //计算相应的值以后,再把结果入栈
  int postfix_len = strlen(postfix);
  stack<int> pos_str;
  int t1,t2,t;
  for(i=0;i<postfix_len;i++)
  {
	  if(postfix[i]!='+'&&postfix[i]!='-'&&postfix[i]!='*'&&postfix[i]!='/')
		  pos_str.push(postfix[i]-'0');
	  else
	  {  
	    t1 = pos_str.top(); pos_str.pop();
	    t2 = pos_str.top(); pos_str.pop();
        switch(postfix[i])
		{
		   case'+': t = t1+t2;break;
		   case'-': t = t2-t1;break;//因为先弹出来的t1是减数,t2是被减数
		   case'*': t = t1*t2;break;
		   case'/': t = t2/t1;break;//因为先弹出来的t1是除数,然后t2是被除数
		   default: exit(0);
		}
		pos_str.push(t);
	   }
   }
   int result = pos_str.top();
   return result;
}


int main()
{
 char *str="5-(4+5)*2*7/4-5/(3+1)";
 int len = strlen(str);
 int relVal=calculate(len,str);
 printf("%d\n",relVal);
 system("pause");
 return 0;
}


第二种方法:利用栈和优先级来算,不过这种方法中间计算的结果也不能大于10,并且不能加括号

#include<stdlib.h>
#include<stdio.h>
#include<iostream>
#include<stack>
using namespace std;


stack<char> OPTR;//运算符
stack<int>  OPND;//运算数


int In(char c)
{  //判断是否为运算符
  switch(c)
  {
  case '+':
  case '-':
  case '*':
  case '/':
  case '#': return 1;
  default:  return 0;
   }
}

char Precede(char t1,char t2) //t1是栈顶元素,t2是原运算式的字符
{   
	
	 if(t1=='#' && t2=='#')
       return '=';
    if(t1=='#')
       return '<';
    if(t2=='#')
       return '>';
    if(t1=='+' || t1=='-')
    {
       if(t2=='+' || t2=='-')
           return '>';
       else
           return '<';
    }
    if(t1=='*' || t1=='/')
       return '>';

}

char Operate(char a,char theta,char b)
{
	char c;
	//a = double(a);
	//b = double(b);
	a = a-48;
	b = b-48;
	//int e,f;
	//e = a - '0';
	//f = b - '0';
	switch(theta)
	{
	case '+': c = a+b+48;
	          break;
	case '-': c = a-b+48;
	          break;
	case '*': c = a*b+48;
	          break;
	case '/': c = a/b+48;
	          break;
     }
	//c = char(c);
	return c;
}

int calcucate(int len, char *expStr)
{   
	//char *expStr1 = expStr;
	//strcat(expStr1,"#");
	int i=0;
	char c,theta,a,b;
	OPTR.push('#');
	c = expStr[i];
	   
		
    char x = OPTR.top();
	while(c!='#' || x!='#')
	{	
		c = expStr[i]; 
	    if(In(c))//是加减乘除运算符之一
		switch(Precede(x,c))
		{
		  case '<':OPTR.push(c);//栈顶元素优先级低 
			       i++;
				   break;
		  case '=':i++;
			       break;
		  case '>':theta = OPTR.top();
			       OPTR.pop();
			       b = OPND.top();
				   OPND.pop();
				   a = OPND.top();
				   OPND.pop();
				   OPND.push(Operate(a,theta,b));
	     }
		else if(c>='0' && c<='9')
		{
			OPND.push(c);
			i++;
		}
		else //c是非法字符
        {
			printf("ERROR\n");
		    exit(0);
		}
		x = OPTR.top();
		//OPTR.pop();
		
 	}
	x = OPND.top();
	return x;
}

int main()
{
 printf("请输入运算式,中间值在0到9之间\n");
 //char *expStr = "4+2*1-3+5#";
 char *expStr = "1-3+2*1+4*1-1-1#";
 int len = strlen(expStr);
 int result = calcucate(len , expStr);
 printf("%c\n",result);
 system("pause");
 return 0;
}

第三种方法:用数组模拟栈的实现,不带括号

#include<stdio.h>
#include<stdlib.h>
#include<string.h>


int calculate(int len,char *expStr)
{
	int* data = (int*)malloc(sizeof(int)*len); 
    char* oper = (char*)malloc(sizeof(char)*len);
    int datatop = -1;
	int opertop = -1;
    int num=0;
	int num1=0;
	int num2=0;
	
	memset(data,0,sizeof(int)*len);
	memset(oper,0,sizeof(char)*len);
    for(int i=0;i<len;i++)
	{
	   if( expStr[i]>='0' && expStr[i]<='9')//如果是数字,就将它压入data栈
		    data[++datatop] = expStr[i]-'0';
	   if(expStr[i]=='+' || expStr[i]=='-')//如果是字符,'+','-',就将它压入oper栈
	       oper[++opertop] = expStr[i];	   
		   if(expStr[i]=='*')//如果是乘号,就把乘号左右两边的数字相乘,将得到的结果放入data中。
		   {
                num1 = data[datatop];
				num2 = expStr[++i]-'0';
				num = num1*num2;
			    data[datatop] = num;
			
		   }
			   
		   if(expStr[i]=='/')
		   {
				num1 = data[datatop];
				num2 = expStr[++i]-'0';
				num = num1/num2;
			    data[datatop] = num;
		   }
	   
	}

    char oper_now;//计算只有加减的运算
    int flag = datatop;
	int data_num = 0,oper_num = 0;
	while(data_num<flag)
	{
		num1 = data[data_num++];
		num2 = data[data_num];
		oper_now = oper[oper_num++];
		if(oper_now=='+')
		{
			num = num1+num2;
			data[data_num] = num;
		}
		if(oper_now=='-')
		{
			num = num1-num2;
			data[data_num] = num;
		}

	}
     return data[data_num];
}

   


int main()
{
 char * str = "2-3-5+4*3-2";
 int len = strlen(str);
 int result=calculate(len,str);
 printf("%d\n",result);
 return 0;
}


以上都是操作数是个位数,如果操作数大于1位,那么我们可以用以下方法来将多个字符转化为数字:


int leftNum = convertToDigit(pInputStr)

<p>int convertToDigit(const char *&str)//将从str开始的数字即其后的数字转换为int,最终str指向下一个运算符或'\0'.</p><p>{</p><p>    int result = 0;</p>
 
    while (isdigit(*str))
    {
        result = result * 10 + (*str - '0');
        str++;
    }
 
    return result;
}


操作数大于1位的四则运算的代码:

#include<stdio.h>  
#include<stdlib.h>  
#include<string.h>  
#include<math.h>
#include<ctype.h>
 
int covertodigit(char *s,int &num)
{
  int m=0;
  while( isdigit(*s) )
  {
	 m = m*10+(*s-'0');
     s++;
	 num++;
  }
  return m;
}

int calculate(int len,char *expStr) 
{
  int *data = (int *)malloc(sizeof(int)*len);
  char *oper = (char *)malloc(sizeof(char)*len);
  int datatop = -1;
  int opertop = -1;
  int sum = 0;
  int m = 0;
  int num = 0;
  for(int i=0;i<len;i++)
  {
	  if(isdigit(expStr[i]))
	  {
		  m = covertodigit(expStr+i,num);
		  i = i+ num-1 ;
	      data[++datatop] = m;
	      num = 0;
	  }
	  else
	  {
	   if(expStr[i]=='+' || expStr[i] =='-')
		  oper[++opertop] = expStr[i];
	   else
	   {
	    if(expStr[i]=='*')
			data[datatop] = data[datatop] * (expStr[++i]-'0');
        if(expStr[i]=='/')
		    data[datatop] = data[datatop] / (expStr[++i]-'0');
	   }
	  }

  }
  sum = data[0];
  int k=0;
  for(int j=1;j<=datatop;j++)
  {
    if(oper[k]=='+')
       sum = sum + data[j];
    if(oper[k]=='-')
	   sum = sum - data[j];
	k++;
  }

  return sum;
}



int main()  
{  
 char * str = "20-3-5+4*3-2";  
 int len = strlen(str);  
 int result=calculate(len,str);  
 printf("%d\n",result);  
 return 0;  
} 


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值