栈实现表达式求值(C语言)

本文介绍如何使用C语言和栈数据结构实现一个能解析并计算含括号复杂表达式的计算器。通过将中缀表达式转换为后缀表达式,再对后缀表达式进行计算,最终得出表达式的值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

刚刚学习C语言的时候很多人就写过计算器,但是当时写的计算器只能进行一步四则运算;对于一次输入(1+2)*3+4这样的运算则没有办法计算。 
本篇博文利用栈这种数据结构实现了支持带括号的表达式求值计算器;

栈有栈底和栈顶指针,元素是先进后出;对于栈的操作最主要的是创建、压栈、弹栈;在实现计算器时,我们输入的表达式叫做中缀表达式,我们需要将其转为后缀表达式;然后利用后缀表达式求取表达式的值;

创建栈

typedef struct LinkList
{
    char operatorAndData;
    struct LinkList *next;
}LinkList,*LinkNode;
typedef struct LinkStack
{
    LinkNode top;
    int count;
}LinkStack;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

创建了两个结构体;LinkList是一个单向链表,保存数据和指向下一个节点的指针(next);LinkStack是栈,保存着栈顶指针和计数;

  1. 初始化
State createStack(LinkStack *S) {
    S->count = -1;
    S->top = NULL;
    return OK;
}
  • 1
  • 2
  • 3
  • 4
  • 5

链栈是没有头结点的,将第一个节点数据域置位NULL,计数器设为-1;表示栈底; 
2. push

State pushStack(LinkStack *S, char data) {
    LinkNode s;
    s = (LinkNode)malloc(sizeof(LinkList));
    s->operatorAndData = data;
    s->next = S->top;
    S->top = s;
    S->count++;
    return OK;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

压栈与前面介绍链表的博文中增加链表节点的方式有差别;增加节点是把链表指针地址传递给子函数,这里是把指针传递给子函数;然后为节点申请空间,完成节点入栈; 
节点入栈是:节点指针域指向当前的top,然后top指向增加的节点(上移);完成入栈; 
3. pop

State popStack(LinkStack *S,char *data) {
    LinkNode p;
    //判断栈空
    if (S->top == NULL || S->count==-1) {
        return ERROR;
    }
    *data = S->top->operatorAndData;
    p = S->top;
    S->top = S->top->next;
    S->count--;
    free(p);
    return OK;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

pop需要判断栈是否为空;完成数据赋值和计数减一,释放节点空间;

中缀表达式和后缀表达式

  1. 中缀表达式转后缀表达式 
    2+(1+2)*2-6; 
    这是一个中缀表达式;我们对扫描到的表示进行处理,数字输出,符号入栈; 
    第一步: 
    输出:2 
    入栈:+ 
    第二步: 
    入栈:( 
    第四步: 
    输出:1、2 
    入栈:+ 
    第五步: 
    当前的总输出是:2、1、2 
    栈中的符号是:+(+ 
    现在扫描到);此时需要栈中符号输出直到遇到(; 
    所以第五步执行完以后: 
    总输出:2 1 2 + 
    栈中剩余元素:+ 
    第六步: 
    栈中+优先级低于* *入栈;2输出; 
    总输出:2 1 2 + 2 
    栈中符号:+ * 
    第七步: 
    -号优先级小于* *号出列; 
    栈中元素:+ - 
    输出:2 1 2 + 2* 
    第八步: 
    数字6输出; 
    输出:2 1 2 + 2 * 6 
    第八步: 
    栈中所有符号输出得到后缀表达式: 
    2 1 2 + 2 * 6 - +
  2. 后缀表达式求值 
    对后缀表达式扫描:数字入栈 
    第一步: 
    2 1 2入栈; 
    读到 + :从栈栈中弹出两个元素,data1;data2;data2+data1入栈; 
    栈中元素:2 3 
    第二步: 
    2入栈; 
    :从栈中弹出两个元素;data2 *data1;3 2=6入栈; 
    栈中元素:2 6 
    第三步: 
    读到元素6,入栈; 
    栈中元素:2 6 6 
    读到-:弹栈;data2 - data1;结果入栈 
    栈中元素: 2 0 
    第四步: 
    +号:弹栈 data2 + data1;结果入栈; 
    栈中元素 2; 
    第五步: 
    弹出栈中元素,为运算结果;

计算器代码:

/*利用链栈实现计算*/
#include<stdio.h>
#define OK 0;
#define ERROR -1
typedef int State;
typedef struct LinkList
{
    char operatorAndData;
    struct LinkList *next;
}LinkList,*LinkNode;
typedef struct LinkStact
{
    LinkNode top;
    int count;
}LinkStack;

//创建链栈(栈是一个没有头结点的单链表)
State createStack(LinkStack *S) {
    S->count = -1;
    S->top = NULL;
    return OK;
}
//push
State pushStack(LinkStack *S, char data) {
    LinkNode s;
    s = (LinkNode)malloc(sizeof(LinkList));
    s->operatorAndData = data;
    s->next = S->top;
    S->top = s;
    S->count++;
    return OK;
}
//pop
State popStack(LinkStack *S,char *data) {
    LinkNode p;
    //判断栈空
    if (S->top == NULL || S->count==-1) {
        return ERROR;
    }
    *data = S->top->operatorAndData;
    p = S->top;
    S->top = S->top->next;
    S->count--;
    free(p);
    return OK;
}
//创建链表用于存储输入表达式
int main() {
    LinkStack infixExpression;
    LinkStack computeStack;
    int i = 0;
    int j = 0;
    char result;
    State state;
    char inExpression[50] = { 0 };
    char postfixExpression[50] = { 0 };
    char postTmp;
    char operatorData1;
    char operatorData2;
    createStack(&infixExpression);
    createStack(&computeStack);
    gets(inExpression);

    //中缀表达式转后缀表达式
    while (inExpression[i]!='\0') {
        if (inExpression[i]<48 || inExpression[i]>57) {
            if (inExpression[i] == 41) {
                if (!(infixExpression.count < 0)) {
                    popStack(&infixExpression, &postTmp);
                    while (postTmp != 40) {
                        postfixExpression[j++] = postTmp;
                        if (!(infixExpression.count < 0))
                            popStack(&infixExpression, &postTmp);
                        else
                            break;
                    }
                }
            }
            else if (inExpression[i] == 43 || inExpression[i] == 45 ) {
                if (!(infixExpression.count < 0)) {
                    popStack(&infixExpression, &postTmp);
                    while (postTmp == 42 || postTmp == 47) {
                        postfixExpression[j++] = postTmp;
                        if (!(infixExpression.count < 0)) {
                            popStack(&infixExpression, &postTmp);
                        }
                        else
                            break;
                    }
                    pushStack(&infixExpression, postTmp);
                }
                pushStack(&infixExpression, inExpression[i]);
            }
            else {
                pushStack(&infixExpression, inExpression[i]);
            }

        }
        else {
            postfixExpression[j++] = inExpression[i];
        }
        i++;
    }
    while (!(infixExpression.count < 0)) {
        popStack(&infixExpression, &postTmp);
        postfixExpression[j++] = postTmp;
    }
    //计算后缀表达式
    i = 0;
    while (i != j) {
        if (postfixExpression[i]<48 || postfixExpression[i]>57) {
            popStack(&computeStack, &operatorData1);
            popStack(&computeStack, &operatorData2);
            if (postfixExpression[i] == 43) {
                postTmp = (operatorData2-48 + operatorData1-48)+48;
                pushStack(&computeStack, postTmp);
            }

            if (postfixExpression[i] == 45) {
                postTmp = (operatorData2 - 48) - 
                    (operatorData1 - 48) + 48;
                pushStack(&computeStack, postTmp);
            }
            if (postfixExpression[i] == 42){
                postTmp = (operatorData2 - 48) *
                    (operatorData1 - 48) + 48;
                pushStack(&computeStack, postTmp);
            }
            if (postfixExpression[i] == 47) {
                postTmp = (operatorData2 - 48) /
                    (operatorData1 - 48) + 48;
                pushStack(&computeStack, postTmp);
            }

        }
        else
            pushStack(&computeStack, postfixExpression[i]);
        i++;
    }
    popStack(&computeStack, &result);
    printf("%c\n", result);
    return OK;
}转载自:栈实现表达式求值(C语言) - 博客频道 - youkuaiyun.com
http://blog.youkuaiyun.com/u011028771/article/details/52954769?locationNum=4&fps=1
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143

输入的表达式的中间结果和最终结果都需要是0-9之间;

在C语言中,可以使用两个实现表达式求值。一个用于存储操作数,另一个用于存储操作符。 具体的实现步骤如下: 1. 创建两个,一个用于存储操作数,另一个用于存储操作符。 2. 从左到右遍历表达式的每个字符。 3. 如果当前字符是数字,则将其转换为操作数,并将其压入操作数。 4. 如果当前字符是操作符,则进行以下操作: - 如果操作符为空,或者当前操作符的优先级大于顶操作符的优先级,则将当前操作符压入操作符。 - 否则,将顶操作符弹出,并从操作数中弹出两个操作数进行运算,将结果压入操作数。重复此过程直到满足条件后,将当前操作符压入操作符。 5. 如果当前字符是左括号"(",则将其压入操作符。 6. 如果当前字符是右括号")",则进行以下操作: - 从操作符中弹出操作符,直到遇到左括号为止。同时从操作数中弹出两个操作数进行运算,将结果压入操作数。 - 弹出左括号"("。 7. 遍历完整个表达式后,如果操作符不为空,则从操作符中弹出操作符,并从操作数中弹出两个操作数进行运算,将结果压入操作数。 8. 最后,操作数中的唯一元素即为表达式求值结果。 下面是一个用两个实现表达式求值的C语言代码示例: ```c #include <stdio.h> #include <stdlib.h> #define MAX_SIZE 100 // 定义操作数和操作符 int operandStack[MAX_SIZE]; char operatorStack[MAX_SIZE]; int operandTop = -1; int operatorTop = -1; // 操作数的相关操作 void pushOperand(int operand) { operandStack[++operandTop] = operand; } int popOperand() { return operandStack[operandTop--]; } // 操作符的相关操作 void pushOperator(char operator) { operatorStack[++operatorTop] = operator; } char popOperator() { return operatorStack[operatorTop--]; } // 获取操作符的优先级 int getPriority(char operator) { if (operator == '+' || operator == '-') return 1; else if (operator == '*' || operator == '/') return 2; else return 0; } // 表达式求值函数 int evaluateExpression(char* expression) { int i = 0; while (expression[i] != '\0') { if (expression[i] >= '0' && expression[i] <= '9') { // 当前字符是数字,将其转换为操作数并压入操作数 int operand = 0; while (expression[i] >= '0' && expression[i] <= '9') { operand = operand * 10 + (expression[i] - '0'); i++; } pushOperand(operand); } else if (expression[i] == '(') { // 当前字符是左括号,将其压入操作符 pushOperator(expression[i]); i++; } else if (expression[i] == ')') { // 当前字符是右括号,进行运算 while (operatorTop != -1 && operatorStack[operatorTop] != '(') { char operator = popOperator(); int operand2 = popOperand(); int operand1 = popOperand(); int result; switch (operator) { case '+': result = operand1 + operand2; break; case '-': result = operand1 - operand2; break; case '*': result = operand1 * operand2; break; case '/': result = operand1 / operand2; break; } pushOperand(result); } // 弹出左括号 popOperator(); i++; } else { // 当前字符是操作符,进行运算 while (operatorTop != -1 && getPriority(expression[i]) <= getPriority(operatorStack[operatorTop])) { char operator = popOperator(); int operand2 = popOperand(); int operand1 = popOperand(); int result; switch (operator) { case '+': result = operand1 + operand2; break; case '-': result = operand1 - operand2; break; case '*': result = operand1 * operand2; break; case '/': result = operand1 / operand2; break; } pushOperand(result); } // 将当前操作符压入操作符 pushOperator(expression[i]); i++; } } // 进行最后的运算 while (operatorTop != -1) { char operator = popOperator(); int operand2 = popOperand(); int operand1 = popOperand(); int result; switch (operator) { case '+': result = operand1 + operand2; break; case '-': result = operand1 - operand2; break; case '*': result = operand1 * operand2; break; case '/': result = operand1 / operand2; break; } pushOperand(result); } // 返回最终结果 return operandStack[operandTop]; } int main() { char expression[MAX_SIZE]; printf("请输入表达式:"); scanf("%s", expression); int result = evaluateExpression(expression); printf("表达式求值结果为:%d\n", result); return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值