【数据结构】前缀后缀表达式求值

本文介绍了前缀(波兰表达式)和后缀(逆波兰表达式)的概念,以及它们在计算过程中的应用。通过代码示例展示了如何进行前缀表达式的递归求值和后缀表达式的栈操作求值。同时提到了中缀表达式转后缀表达式的基本思路,强调实际处理时可能存在的细节问题和解决方法。

前缀表达式和后缀表达式是什么呢?

对于任何算数表达式来说,如果每个操作符跟在它的两个操作数之后,而不是两个操作数之间,那么这个表达式就是后缀表达,又称为逆波兰表达式,如:

3 5 + 7 * 1 -

如果是跟在两个操作数之间,那么这个表达式就是中缀表达式,如:

(3 + 5) * 7 - 1

如果是在两个操作数之前,那么这个表达式就是前缀表达式,又称波兰表达式,如:

-*+3 5 7 1

前缀表达式求值,思路如下:

因为前缀表达式,操作符肯定都在前面,因此把操作符一一入栈:

这里写图片描述

然后,如果遇到数字了,就把取出一个操作符,再得到两个操作数,进行处理然后继续循环,直到所有的操作数都处理完毕

代码如下:

int PreFix(SeqStack* seq,char* str) {
    if (seq == NULL || str == NULL) {
        return;
    }
    int num1 = 0;
    int num2 = 0;
    int flag = 0;
    //循环处理直到遍历完表达式
    while (*str != '\0') {
        if (*str == '-' || *str == '+' || *str == '*') {
            SeqStackPush(seq, *str);
        }
        else {
            if (flag == 0) {
            //由于不知道咋处理,所以我设了一个标志,只有第一次是从表达式中获取两个操作数的
                num1 = *str - '0';
                num2 = *++str - '0';
                flag = 1;
            }
            else {
                num2 = *str - '0';
            }
            //从栈中取出操作符
            char s = SeqStackTopValue(seq);
            SeqStackPop(seq);
            if (s == '+') {
                num1 = num1 + num2;
            }
            if (s == '-') {
                num1 = num1 - num2;
            }
            if (s == '*') {
                num1 = num1 * num2;
            }
        }
        str++;
    }
    return num1;
}

#if 1
int main() {
    char* str = "-*+3571";
    SeqStack seq;
    SeqStackInit(&seq);
    int num = PreFix(&seq, str);
    printf("expcet 55, actual :%d\n", num);
    system("pause");
    return 0;
}
#endif

注意,我这里的数字都是个位数字,我就不改这段代码了,如果遇到两位以上的数字可以用以下这段代码:

while(*str >= '0' && *str <= '9') {
    num = num*10 + (num - '0');
}

前缀表达式的递归求法:

char* str = "-*+3571"; int i;
int PreFix2() {
    int num = 0;
    if (*str == '+') {
        str++;
        return PreFix2() + PreFix2();
    }
    if (*str == '-') {
        str++;
        return PreFix2() - PreFix2();
    }
    if (*str == '*') {
        str++;
        return PreFix2() * PreFix2();
    }
    if (*str >= '0' && *str <= '9') {
        num = *str++ - '0';
    }
    return num;
}

中缀表达式的求表达式我没写,但是有中缀表达式转换后缀表达式:

例如这个中缀表达式:(3 + 5) * 7 - 1 ,要想转换成后缀表达式,就是遇到操作符就先保存起来,如果接下来遇到‘)’符号,再把保存起来的操作符加上去,然后就继续循环直到表达式结束

int main(int argc, char* argv[]) {
    char* a = argv[1];
    int i, N = strlen(a);
    SeqStack seq;
    SeqStackInit(&seq);
    for (i = 0; i < N; ++i) {
        if (a[i] == ')') {
            printf("%c", SeqStackTopValue(&seq));
            SeqStackPop(&seq);
        }
        if (a[i] == '+' || a[i] == '*') {
            SeqStackPush(&seq, a[i]);
        }
        if (a[i] >= '0' && a[i] <= '9') {
            printf("%c", a[i]);
        }
    }
}

后缀表达式求值也是用到栈,如果遇到操作数就把操作数压栈,如果遇到操作符就出栈两个操作数然后运算再把运算后的值压入到栈里,再继续遍历表达式,直到表达式完成,栈顶元素(也是栈里唯一的元素)就是求出的值

代码如下:

int Suf_Result(SeqStack* seq1, char* exp, int size) {
    if (seq1 == NULL) {
        printf("栈指针传入错误!\n");
        return 0;
    }
    if (exp == NULL) {
        printf("表达式为空!\n");
        return 0;
    }
    if (size == 0) {
        return 0;
    }
    // 1.把这个表达式逆序压栈
    char* str = exp + size - 1;
    while (str != exp) {
        SeqStackPush(seq1, *str);
        str--;
    }
    SeqStackPush(seq1, *str);
    int arr[12];
    int sz = 0;
    while (!SeqStackEmpty(seq1)) {
        char ch = SeqStackTopValue(seq1);
        SeqStackPop(seq1);
        if (ch >= '0' && ch <= '9') {
            arr[sz++] = ch - '0';
        }
        else if(ch == '+' || ch == '-' || ch == '*') {
            int num1 = arr[sz - 1];
            sz--;
            int num2 = arr[sz - 1];
            sz--;
            if (ch == '+') {
                arr[sz++] = num1 + num2;
            }
            else if (ch == '-') {
                arr[sz++] = num2 - num1;
            }
            else {
                arr[sz++] = num1 * num2;
            }
        }
    }
    return arr[sz - 1];
}

这里跟前缀是一样的,如果数字是两位或者三位就用上面那个循环,如果是遇到空格了也用一个循环跳过空字符,比如:

while(*str == ' ') str++;

这里只是简单的写了一下前缀后缀的求值,包括中缀转后缀,好多地方可能会有一些bug,但是大体上思路就是这样

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值