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

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

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

创建栈

typedef struct LinkList
{
    char operatorAndData;
    struct LinkList *next;
}LinkList,*LinkNode;
typedef struct LinkStack
{
    LinkNode top;
    int count;
}LinkStack;

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

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

链栈是没有头结点的,将第一个节点数据域置位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;
}

压栈与前面介绍链表的博文中增加链表节点的方式有差别;增加节点是把链表指针地址传递给子函数,这里是把指针传递给子函数;然后为节点申请空间,完成节点入栈;
节点入栈是:节点指针域指向当前的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;
}

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;
}

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

  • 33
    点赞
  • 115
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值