C语言实现中缀表达式转化为逆波兰表达式

1,563 阅读3分钟

题目:

设计一个算法,将一般算术表达式转化为逆波兰表达式,并求逆波兰表达式的值。

分析:

(1)一般算术表达(中缀表达),如#3*(4+2)/2-5#,#为表达式界定符,逆波兰 表达式(后缀表达式),如前述表达的后缀表达式为:3 4 2 + * 2 / 5 -。

(2)设中缀表达式 的运算符有+、-、*、/、#五种,运算符的优先级别从高到低为()、*、/、+、-、#;有 括号先算括号内,再算括号外的,多层括号由内向外进行。

(3)中缀表达式转换为后缀表达式需要用到一个临时栈 optr 暂存运算符。

伪代码实现

一、中缀表达式转化为后缀表达式

1.将栈 optr 初始化为#;
2.从左至右依次扫描表达式的每个字符,执行下述操作
    2.1 若当前字符是 运算对象,则输出该字符,处理下一个字符;
    
    2.2 若当前字符是 运算符 且优先级别比栈 optr 的栈顶运算符的优先级高,
        则将该字符入栈 optr,处理下一个字符;
        
    2.3 若当前字符是 运算符 且优先级别比栈 optr 的栈顶运算符优先级别低,
        则将栈 optr 的栈顶元素弹出并输出,将当前字符入栈optr,处理下一个字符;
        
    2.4 若当前字符是 运算符 且优先级别与栈optr的栈顶运算符的优先级相等,
        则将栈 optr 的栈顶元素弹出,将当前字符入栈optr,处理下一个字符。

二、表达式的计算

1.初始化栈 opnd 为空;
2.从左到右依次扫描后缀表达式(逆波兰表达式)的每一个字符,执行下述操作;
    2.1 若当前是运算对象,则入栈 opnd,处理下一个字符;
    2.2 若当前字符是运算符,则从栈 opnd 出栈两个运算对象,执行运算并
        将结果入栈 opnd,处理下一个字符;
3.输出栈 opnd 的栈顶元素,即表达式的运算结果。

代码实现

一、中缀表达式转化为后缀表达式

//将中缀表达式转化为后缀表达式(逆波兰式)
void NifixPost(char *nifix, char *postfix){
  int i = 0, j = 0;
  Sqstack *optr;
  optr = InitStack();
  Push(optr, '#');
  while (nifix[i] != '#') {
    if(nifix[i] == '(')
    {
      Push(optr, '(');
    }

    else if (nifix[i] == ')')
    {
      while (GetTop(optr) != '('){
        postfix[j++] = Pop(optr);
      }
      Pop(optr);
    }

    else if ((nifix[i] >= '0' && nifix[i] <='9') || nifix[i] == '.'){
      while ((nifix[i] >= '0' && nifix[i] <='9') || nifix[i] == '.') {
        postfix[j++] = nifix[i++];
      }
      postfix[j++] = ' ';
      i--;
    }

    else {
      char s1, optrtop;
      s1 = nifix[i];
      optrtop = GetTop(optr);
      if (CtoRank(s1) <= CtoRank(optrtop)) {
        postfix[j++] = Pop(optr);
        i--;
      }
      else {
        Push(optr, s1);
      }

    }
    i++;
  }
    while (IsEmpty(optr) != -1){
      postfix[j++] = Pop(optr);
    }
    postfix[j] = '\0';

  printf("\n");
}

二、表达式计算

// 将字符串转化为浮点数
double Myatof(char *str){
  double m=0,n=0,x=1;
	int flag=1;
	while(*str!='\0')
	{
		if(*str<'0'|| *str >'9' )
		{	
			if(*str =='.')   //判断小数点前后
			{
				flag=0;
				str++;
				continue;
			}
			return 0;
		}
		if(flag==1)  //小数点前整数部分
		{	m*=10;
			m+=*str-'0';
		}
		else  //小数部分
		{
			x*=0.1;
			n+=x*(*str-'0');
		}
		str++;
	}
	return m+n;
}

//计算两个浮点数
double ComputeTwoNum (double a,double b,char c) {
  double temp ;
  switch(c)
  {
    case '+':
    temp = a + b;
    break;
    case '-':
    temp = a-b;
    break;
    case '*':
    temp = a * b;
    break;
    case '/':
    temp = a / b;
    break;
    case '^':
      {
        int i = 0;
        temp = 1;
        while (fabs(i-b) > 1e-6) {
          temp *= a;
          i++;
        }
      }
  }

  return temp;
}

//遍历后缀表达式,计算
double ComputeExpresion (char *postfix) {
  int i = 0,j;
  char currentExp[STACK_SIZE];
  printf("\n");

  while (postfix[i] != '#') 
  {
    if(postfix[i] >= '0' && postfix[i] <= '9' || postfix[i] == '.')
    {
      j = 0;
      while (postfix[i] >= '0' && postfix[i] <= '9' || postfix[i] == '.')
      {
        currentExp[j++] = postfix[i++];
      }
      currentExp[j] = '\0';
      OPTD[++TopTd] = Myatof(currentExp);

    } else if (postfix[i] == ' ') {
      i++;
    } 
    else // 当前字符是运算符
    { 
      double a, b;
      // b = Pop(optd);
      // a = Pop(optd);
      b = OPTD[TopTd--]; //这里使用的是一个全局定义的 double型数组和全局定义的int型TopTd作为指针,肯定是不好的的,现在不想改了
      a = OPTD[TopTd];
      OPTD[TopTd] = ComputeTwoNum(a, b, postfix[i]);
		i++;
    }    

  }
  return OPTD[TopTd]; 
}