3

我正在学习波兰符号,我尝试了一个中缀到后缀转换的程序。

对于 + 和 - 等运算符,我的程序执行得很好。但是对于正确关联的幂运算,它不能正常工作。

例如:表达式 A^B^C 应转换为 ABC^^ ,而我使用的算法将其转换为 AB^C^。

使用的算法是:

Define a stack array.
Scan each character in the infix string
If it is between 0 to 9, append it to postfix string.
If it is left parenthesis push to stack
If it is operator *,+,-,/,%,^ then 
          If the stack is empty push it to the stack
          If the stack is not empty then start a loop:
                             If the top of the stack has higher precedence
                             Then pop and append to output string
                             Else break
                     Push to the stack

If it is right parenthesis then
            While stack not empty and top not equal to left brace
            Pop from stack and append to output string
            Finally pop out the left brace.

If there is any input in the stack pop and append to the Postfix string.

我应该在算法中进行哪些更改,以便它也适用于右关联运算符。?

我的代码是:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
# define MAX 100
int top=-1;
char infix[100],postfix[100];
char stack[100];
int priority(char symbol)
{
    switch(symbol)
    {
        case '(':return 0;
        case '+':
        case '-':
                 return 1;
        case '/':
        case '*':
        case '%':
                 return 2;
        case '^':
                 return 3;
        default :return 0;
    }
}
void push(char symbol)
{
    if(top==MAX-1)
    {
        printf("Stack overflow:\n");
        exit(1);
    }
    top=top+1;
    stack[top]=symbol;
}
char pop()
{
    if(top==-1)
    {
        printf("Stack underflow:\n");
        exit(1);
    }
    return stack[top--];
}
void infix_to_postfix()
{
    int i,p=0;
    char symbol,next;
    for(i=0;i<strlen(infix);i++)
    {
        symbol=infix[i];

            switch(symbol)
            {
                case '(':push(symbol);
                         break;
                case ')':while((next=pop())!='(') 
                         {
                            postfix[p]=next;
                            p++;
                         }
                         break;
                case '+':
                case '-':
                case '*':
                case '/':
                case '%':
                case '^':
                while(top!=-1 && priority(stack[top])>=priority(symbol))
                {//or stack is empty
                    postfix[p]=pop();
                    p++;
                }
                push(symbol);
                break;
                default://if operand comes
                postfix[p]=symbol;
                p++;
            }
    }
    while(top!=-1)
    {
        postfix[p]=pop();
        //printf("%c",pop());
        p++;
    }
    postfix[p]='\0';
}
int main()
{
    printf("Enter the infix expression:\n");
    scanf("%s",infix);
    printf("The post fix expression is:\n");
    infix_to_postfix();
    printf("->  %s",postfix);
    return 0;
}
4

3 回答 3

3

经典的解决方案是 Dijkstra 的“Shunting Yard”算法:http ://en.m.wikipedia.org/wiki/Shunting_yard_algorithm

于 2013-06-25T17:35:00.510 回答
0

使用我写的类工具

工具.h

static class Tools
{
   public:
       static char* toPostfix(char* source);
       static double calculatePostfix(char* source);
       static bool contain(char* source,char character);
 };

工具.cpp

#include "stdafx.h"
#include "Tools.h"
#include <stack>
#include <iostream>
#include <string>

using namespace std;

char* Tools::toPostfix(char* source)
{
    stack<char> symbol;
    string postfix = "";
    int i = 0;
    char variables[] = { "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" };
    bool find = false;

    while (*source != '\0')
    {
        switch (*source)
        {
        case '+':
        case '-':
        case '*':
        case '/':
            symbol.push(*source); 
            break;
        case ')':
            postfix += symbol.top();
            symbol.pop();
        default:
            find = Tools::contain(variables, *source);
            if (find)
            {
                 postfix += *source;
                 find = false;
             }

        }
        source++;
    }
    // attach other operator in stack(Pop All)
    while (!symbol.empty())
    {
         postfix += symbol.top();
         symbol.pop();
     }

     char* p = new char(postfix.length());
     const char* o = postfix.c_str();
     for (int i = 0; i < postfix.length(); i++)
         p[i] = o[i];
     return p;
}

double Tools::calculatePostfix(char* source)
{
    char numbers[] = { "0123456789" };
    stack<double> number;
    for (int i = 0; i < strlen(source); i++)
    {
        char character = source[i];
        if (Tools::contain(numbers, character))
        {
            number.push(atof(&character));
        }
        else
        {
            double number1, number2;
            switch (character)
            {
            case '+':
                number2 = number.top();
                number.pop();
                number1 = number.top();
                number.pop();
                number.push(number1 + number2);
                break;
            case '-':
                number2 = number.top();
                number.pop();
                number1 = number.top();
                number.pop();
                number.push(number1 - number2);
                break;
            case '*':
                number2 = number.top();
                number.pop();
                number1 = number.top();
                number.pop();
                number.push(number1 * number2);
                break;
            case '/':
                number2 = number.top();
                number.pop();
                number1 = number.top();
                number.pop();
                number.push(number1 / number2);
                break;
            }
        }
    }
    return number.top();
}

bool Tools::contain(char* source, char character)
{
    int size = strlen(source);
    for (int i = 0; i < size ; i++)
    {
        if (source[i] == character)
            return true;
    }
    return false;
}

用法 :

 std::cout << "postFix : " << Tools::toPostfix("a+(b*c+t)") << std::endl;
 std::cout << "Answer : " << Tools::calculatePostfix("24*95+-") << std::endl;
于 2014-10-10T22:21:41.040 回答
-2

希望这听起来不太迂腐,但我建议你改变算法的整个方法。因为每次添加新操作符时,这种方法确实需要大量调整。更重要的是,随着运算符变得越来越复杂,您的方法将变得非常不实用。

我相信一个更正确但需要更多工作的解决方案是实际解析您的中缀表达式并从中构建二进制表达式树。

这应该不是那么难,因为算术表达式的语法是在互联网上定义的。在找到适合您需要的语法后,执行解析,构建树,当您拥有这些时,您可以通过执行树的后序遍历来获得后缀符号。

关于二叉表达式树的Wikipedia 文章可能是您开始编写有关此主题的文档的好地方。希望这可以帮助!

于 2013-06-25T08:02:12.660 回答