如何将公式中的中缀表达式转换成后缀表达式?

数据结构老师发了这么一道题:

将中缀表达式转换为后缀表达式

以下是c语言实现的中缀表达式代码(粘贴老师的)

#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "math.h"
#pragma region 使用粘贴符定义复用栈代码
#define DelcareStack(type)                                              \
    typedef struct type##_Node                                          \
    {                                                                   \
        type data;                                                      \
        struct type##_Node *next;                                       \
    } type##Stack;                                                      \
    int type##StackEmpty(type##Stack *stack)                            \
    {                                                                   \
        return stack == NULL;                                           \
    }                                                                   \
    void type##StackPush(type##Stack **stack, type c)                   \
    {                                                                   \
        type##Stack *node = (type##Stack *)malloc(sizeof(type##Stack)); \
        node->data = c;                                                 \
        node->next = *stack;                                            \
        *stack = node;                                                  \
    }                                                                   \
    int type##StackPop(type##Stack **stack, type *data)                 \
    {                                                                   \
        if (*stack == NULL)                                             \
            return 0;                                                   \
        else                                                            \
        {                                                               \
            *data = (*stack)->data;                                     \
            *stack = (*stack)->next;                                    \
            return 1;                                                   \
        }                                                               \
    }                                                                   \
    int type##StackTop(type##Stack *stack, type *data)                  \
    {                                                                   \
        if (stack == NULL)                                              \
            return 0;                                                   \
        else                                                            \
        {                                                               \
            *data = stack->data;                                        \
            return 1;                                                   \
        }                                                               \
    }
#pragma endregion 复用栈
DelcareStack(char)
DelcareStack(float)
int higherThan(char opInExp, char opInStack)
{
    char *ops = "+-*/\%^";
    int rate[6] = {0, 0, 1, 1, 1, 2};
    int expRate, stackRate;
    if (opInExp == ')')
        return 0;
    if (opInExp == '(')
        return 1;
    if (opInStack == '(')
        return 1;

    expRate = rate[(char *)strchr(ops, opInExp) - ops];
    stackRate = rate[(char *)strchr(ops, opInStack) - ops];
    return expRate - stackRate;
}
float calc(float a, float b, char op)
{
    switch (op)
    {
    case '+':
        return a + b;
    case '-':
        return a - b;
    case '*':
        return a * b;
    case '/':
        return a / b;
    case '%':
        return (int)a % (int)b;
    case '^':
        return pow(a, b);
    }
}
float calcExp(char *expression)
{
    charStack *op=NULL;  //运算符栈
    floatStack *ob=NULL; //对象栈
    char *p = expression, opInStack;
    float a, b;
    while (*p)
    {
        if (strchr("0123456789", *p))
        {
            floatStackPush(&ob, *p - 48);
            p++;
        }
        else
        {
            if (charStackEmpty(op))
            {
                charStackPush(&op, *p);
                p++;
            }
            else
            {
                charStackTop(op, &opInStack);
                if (higherThan(*p, opInStack) > 0)
                {
                    charStackPush(&op, *p);
                    p++;
                }
                else
                {
                    charStackPop(&op, &opInStack);
                    if (opInStack != '(')
                    {
                        floatStackPop(&ob, &b);
                        floatStackPop(&ob, &a);
                        printf("calculating %f%c%f\n", a, opInStack, b);

                        floatStackPush(&ob, calc(a, b, opInStack));
                    }
                    else
                        p++;
                }
            }
        }
    }
    while (!charStackEmpty(op))
    {
        floatStackPop(&ob, &b);
        floatStackPop(&ob, &a);
        charStackPop(&op, &opInStack);
        printf("calculating %f%c%f\n", a, opInStack, b);
        floatStackPush(&ob, calc(a, b, opInStack));
    }
    floatStackPop(&ob, &a);
    return a;
}
int main()
{
    printf("%.2f", calcExp("3*2^(4+2*2-1*3)-5"));
    getchar();
}

什么是复用栈呢,在网上看到这么一句话

最开始写的栈,通过宏来改变元素数据类型,在同一程序中只能用于一种数据类型,想要用于多种数据类型则要复制代码并改名。那么,有没有方法不复制代码就可以用于多种数据类型?

源于

weixin_30375247https://blog.csdn.net/weixin_30375247

说白了,使用复用栈是因为你不知道存储的数据类型是什么,比如一个公式1+1*2,里面既有整型数据,也有字符数据。

从理论上,如何将中缀表达式转换为后缀表达式?

以下是CSDN大佬的总结:

2.1.1 栈的应用-四则运算表达式求值规则
  1.设定运算符栈;
  2.从左到右遍历中缀表达式的每个数字和运算符;
  3.若当前字符是数字,则直接输出成为后缀表达式的一部分;
  4.若当前字符为运算符,则判断其与栈顶运算符的优先级,若优先级大于栈顶运算符,则进栈;若优先级小于栈顶运算符,退出栈顶运算符成为后缀表达式的一部分,然后将当前运算符放入栈中;
  5.若当前字符为“(”,进栈;
  6.若当前字符为“)”,则从栈顶起,依次将栈中运算符出栈成为后缀表达式的一部分,直到碰到“(”。将栈中“(”出栈,不需要成为后缀表达式的一部分,然后继续扫描表达式直到最终输出后缀表达式为止。

源于

没错酷呆https://blog.csdn.net/qq_43290883由于博主实力有限,不能在老师的原基础上进行更改(换句话,老师写的代码我看不懂...)就只能自己另寻思路了(看的懂上面代码的大佬们可以教教我哈~Q2214891127)

Java代码实现如下

import java.util.Scanner;
import java.util.Stack;

/**
 * 中缀表达式转换为后缀表达式
 * @Author Asunne
 * @Date 2022/09/28
 */
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入一段公式");
        String str1 = sc.next(); // str1用来存储用于录入中缀表达式
        String str2 = ""; // str2用来记录对应的后缀表达式
        System.out.println(str1);

        boolean flag = true; // 定义标识符,用来判断操作符的优先级
        Stack<Character> st = new Stack<Character>(); // 定义存放Character类型的栈
        int num = str1.length(); // 记录要循环的次数
        int i=0; // i用来遍历str1
        while((num--)>0)
        {
            if(str1.charAt(i)<='9'&&str1.charAt(i)>='0')
                str2+=str1.charAt(i);
            else if(str1.charAt(i)=='(')
                st.push(str1.charAt(i));
            else if(str1.charAt(i)==')')
            {
                while(st.peek()!='('){
                    str2+=st.pop(); // 取出括号之间的所有操作符
                }
                st.pop(); // 取出左括号
            }
            else {
                // flag如果为true则意味着操作符的优先级高于栈顶操作符,应该压入栈中,否则一直取出栈顶元素
                if(!st.empty())
                    flag = compare(st.peek(),str1.charAt(i));
                while(flag == false && !st.empty())
                {
                    str2 += st.pop();
                    if(st.empty())
                        flag = true;
                    else
                        flag = compare(st.peek(),str1.charAt(i));
                }
                st.push(str1.charAt(i));
            }
            System.out.println(str1.charAt(i));
            if(!st.empty())
                System.out.println(st.peek());
            System.out.println(str2);
            System.out.println("------------------");
            i++;
        }
        while(!st.empty())
            str2 += st.pop();
        System.out.println("用户输入的中缀表达式:"+str1);
        System.out.println("公式对应的后缀表达式:"+str2);
    }
    static  boolean compare(Character a,Character b){
        int k1,k2; // k1和k2分别用来记录a,b操作符对应的权值
        // 使用Switch语句对k1和k2进行赋权
        k1=k2=0;
        switch (a){
            case '(':
                k1 = -1;
                break;
            case '+':
                k1 = 1;
                break;
            case '-':
                k1 = 1;
                break;
            case '*':
                k1 = 2;
                break;
            case '/':
                k1 = 2;
                break;
            case '^':
                k1 = 3;
                break;
        }
        switch (b){
            case '+':
                k2 = 1;
                break;
            case '-':
                k2 = 1;
                break;
            case '*':
                k2 = 2;
                break;
            case '/':
                k2 = 2;
                break;
            case '^':
                k2 = 3;
                break;
        } // 两个Switch语句显得代码有点重复,感兴趣的读者可以自行优化
        return (k2>k1);
    }
}

测试用例:(2*(9+6/3-5)+4)

测试结果:

C语言实现如下(有一点问题,呜呜呜~~~博主是个废物):

/*将中缀表达式转换为后缀表达式*/
/**
 * Author: Asunne
 * Date: 2022/09/28
 **/
#include <stdio.h>
#include <stdlib.h>
typedef char ElementType; // 此方法定义数据类型,易于后续的维护
typedef enum
{
    true,
    false
} bool; // c语言没有自带的布尔值类型,需要自己定义
typedef struct Node
{
    ElementType character[100];
    int top; // 用于记录栈顶位置
} Stack;     // 使用顺序栈实现需求
void transform(char str[]);
bool compare(char a, char b);
int main()
{
    char str[10000];
    gets(str);
    transform(str);
}
void transform(char str[])
{
    Stack S;
    S.top = -1;
    int i = -1;          // i用来遍历输入的字符数组
    int n = strlen(str); // 记录字符数组的总长度
    bool flag; // 定义标识符
    while (n--)
    {
        i++;
        if (str[i] == "(")
            S.character[++S.top] = str[i];
        else if (str[i] <= '9' && str[i] >= '0')
            printf("%c", str[i]); // 如果读到数字,直接输出
        else if (str[i] == ')')
        {
            while (S.character[S.top] != '(')
            {
                printf("%c", S.character[S.top--]);
            }
            S.top--;
            continue;
        }
        else
        {
            if(S.top == -1)
            {
                S.character[++S.top] = str[i];
                continue;
            }
            while(flag == false)
            {
                printf("%c",S.character[S.top--]);
                flag = compare(S.character[S.top],str[i]);
            }
            S.character[++S.top] = str[i];
        }
    }
    while(S.top!=-1)
        printf("%c",S.character[S.top--]);
}
bool compare(char a, char b)
{
    int k1, k2; // k1和k2分别用来记录a,b操作符对应的权值
    k1 = k2 = 0;
    // 使用Switch语句对k1和k2进行赋权
    switch (a)
    {
    case '(':
        k1 = -1;
        break;
    case '+':
        k1 = 1;
        break;
    case '-':
        k1 = 1;
        break;
    case '*':
        k1 = 2;
        break;
    case '/':
        k1 = 2;
        break;
    case '^':
        k1 = 3;
        break;
    }
    switch (b)
    {
    case '+':
        k2 = 1;
        break;
    case '-':
        k2 = 1;
        break;
    case '*':
        k2 = 2;
        break;
    case '/':
        k2 = 2;
        break;
    case '^':
        k2 = 3;
        break;
    } // 两个Switch语句显得代码有点重复,感兴趣的读者可以自行优化
    if(k2 > k1)
        return true;
    return false;
}

测试样例:2+3*(7-4)+8/4

测试结果(这是个错误的结果,不管了):

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值