完整代码||算术表达式求解(C++)

juster数据结构实验3:算术表达式求解(附完整代码)


1、项目概述

1.1项目目标和主要内容

项目目标:设计一个简单的算术表达式计算器。
开发平台:Visual Studio 2022 x64
语言:C++
主要内容:

【基本要求】

实现标准整数类型的四则运算表达式的求值(包含括号,可多层嵌入).

【测试数据】

(30+270)/3-123
5+(9*(62-37)+15)*6
要求自行设计非法表达式,进行程序测试,以保证程序的稳定运行。

【实现提示】

可以设计以下辅助函数
status isNumber(char ReadInChar); //视ReadInchar 是否是数字而返回 TRUE 或 FALSE 。
int TurnToInteger(char IntChar); // 将字符’0’.’9’ 转换为整数 9

2、项目设计

2.1基本知识

1.算术表达式求值 :参与运算的数据(即操作数)可以为整数或实数,运算符(即操作符)为+、-、、/(加、减、乘、除)等二元操作符,包括圆括号;如 :
5
6+10-25=15 6+(5-4/2)*3=15
2.运算规则:
先乘除,后加减,从左到右计算,先括号内,后括号外;
3.表达式:
中缀表达式 A+(B-C/D)E
中缀表达式 A+(B-C/D)E
例子:Exp= a
b +(c-d/e)f
PostExp=ab
cde/-f
+
4.
在这里插入图片描述

2.2使用方法:双栈算符优先级法

•双栈算符优先级法为了实现表达式求值,需要设置两个栈:
•一个是运算符栈op,用于寄存运算符;
•另一个成为操作数栈Opnd,用于寄存运算数和运算结果。
在这里插入图片描述
在这里插入图片描述
求值的处理过程是自左至右扫描表达式的每一个字符:
1、当扫描到的是运算数,则将其压入栈OPND,
2、当扫描到的是运算符时:
如这个运算符比OP栈顶运算符的优先级高,则入栈;
如这个运算符比OP栈顶运算符优先级低,则从OPND栈中弹出两个运算符,从栈OP中弹出栈顶运算符进行运算,并将运算结果压入栈OPND。
3、继续处理当前字符,直到遇到结束符为止。

3、程序运行结果

在这里插入图片描述

图3-1 测试运行结果

4、总结

4.1 项目的难点和关键点

1.理解和使用双栈法。
2.在此基础上,了解并使用单栈法。

4.2 心得体会

1.多去阅读相关的资料,看看别人的思路是怎么样。
2.多去请教老师、同学、会的人,学习他们怎么教,自己会了再去教别人。

5、参考文献

参考资料1
老师资料及网上资源等

6、项目源码

#include <stdio.h>
#include <stdlib.h>
#include <memory.h>

// 定义双向栈大小
#define DSTACK_SIZE 40

// 定义双向栈数据结构
typedef struct dStack_s
{
    int data[DSTACK_SIZE];
    unsigned top;          // 指向数据侧栈顶
    unsigned base;         // 指向运算符侧栈顶
}dStack_t;

// 函数声明
int expr(const char*);    // 计算函数

void stackInit(dStack_t**);     // 初始化函数
void operate(dStack_t*);        // 计算函数
int  IsOpr(char);                // 判断输入字符是否运算符
char Precede(char, char);        // 判断运算符的优先级
void PushNum(dStack_t*, int);   // 数字压栈
int  PopNum(dStack_t*);         // 数字出栈
int  GetTopNum(dStack_t*);      // 取数据侧栈顶数字
void PushOpr(dStack_t*, char);  // 运算符压栈
char PopOpr(dStack_t*);         // 运算符出栈
char GetTopOpr(dStack_t*);      // 取运算符侧栈顶运算符


void main(void)
{
    char* equation = NULL;
    char ch = 0;
    int i = 0;

    equation = (char*)malloc(DSTACK_SIZE * sizeof(char));
    if (NULL == equation)
    {
        printf("main:Insufficient Memory!\n");
        exit(0);
    }
    memset(equation, 0, DSTACK_SIZE * sizeof(char));

    printf("Input Formula: Exp. 3-7*(2+1)/2=\n");
    ch = getchar();
    for (i = 0; ch != '\n'; i++)
    {
        if (' ' == ch)   // 过滤掉等式中的空格,其他非法字符在后面检查
        {
            continue;
        }
        *(equation + i) = ch;
        ch = getchar();
    }
    *(equation + i) = '\0';

    printf("%d\n", expr(equation));
    free(equation);
}

/* 利用双向栈算法的计算函数 */
int expr(const char* equation)
{
    char ch = 0;
    int digit = 0;
    int flag = 0;        // 用于标识负号
    int finalKey = 0;    // 存放最后运算结果
    dStack_t* pdStack = NULL;

    if (NULL == equation)
    {
        printf("expr:Insufficient Memory!\n");
        exit(0);
    }

    stackInit(&pdStack);
    PushOpr(pdStack, '=');

    ch = *(equation++);
    if ('-' == ch)       // 特殊情况1:首字符为'-',视为负号
    {
        ch = *(equation++);
        flag = 1;
    }
    while (ch != '=' || GetTopOpr(pdStack) != '=')  // 读入字符与运算符栈顶字符均为'='时结束运算
    {
        if (0 == IsOpr(ch))                  // 若输入为数字,可输入多位数
        {
            digit = ch - '0';
            ch = *(equation++);
            while (0 == IsOpr(ch))
            {
                digit = 10 * digit + ch - '0';
                ch = *(equation++);
            }
            if (1 == flag)
            {
                digit = -digit;
                flag = 0;
            }
            PushNum(pdStack, digit);
        }
        else if (1 == IsOpr(ch))
        {
            if (('-' == ch) && ('(' == *(equation - 2))) // 特殊情况2:若字符'-'紧接'('之后,视前者为负号
            {
                ch = *(equation++);
                flag = 1;
            }
            else
            {
                switch (Precede(GetTopOpr(pdStack), ch))  // 比较栈顶运算符和输入运算符的优先级
                {
                case '<':
                {
                    PushOpr(pdStack, ch);
                    ch = *(equation++);
                    break;
                }
                case '=':
                {
                    PopOpr(pdStack);
                    ch = *(equation++);
                    break;
                }
                case '>':
                {
                    operate(pdStack);
                    break;
                }
                default:
                {
                    printf("Anomaly Result!\n");
                    exit(0);
                }
                }
            }
        }
        else
        {
            printf("Illegal input!\n");
            exit(0);
        }
    }
    finalKey = GetTopNum(pdStack);
    free(pdStack);
    return finalKey;
}

/* 四则运算函数 */
void operate(dStack_t* stack)
{
    int key = 0;
    int topDigit = 0;
    int hypDigit = 0;
    if (NULL == stack)
    {
        printf("operate:Insufficient Memory!\n");
        exit(0);
    }

    topDigit = PopNum(stack);
    hypDigit = PopNum(stack);
    switch (PopOpr(stack))
    {
    case '+':
    {
        key = hypDigit + topDigit;
        break;
    }
    case '-':
    {
        key = hypDigit - topDigit;
        break;
    }
    case '*':
    {
        key = hypDigit * topDigit;
        break;
    }
    case '/':
    {
        if (0 == topDigit)
        {
            printf("Divisor cannot be zero!\n");
            exit(0);
        }
        key = hypDigit / topDigit;
        break;
    }
    default:
    {
        printf("Illegal Operator!\n");
        exit(0);
    }
    }
    PushNum(stack, key);
}

/* 双向栈初始化函数 */
void stackInit(dStack_t** stack)
{
    *stack = (dStack_t*)malloc(sizeof(dStack_t));
    if ((NULL == *stack) || (NULL == stack))
    {
        printf("stackInit:Insufficient Memory!\n");
        exit(0);
    }

    memset((*stack)->data, 0, DSTACK_SIZE * sizeof(int));
    (*stack)->top = -1;
    (*stack)->base = DSTACK_SIZE;
}

/* 数字压栈 */
void PushNum(dStack_t* stack, int digit)
{
    if (NULL == stack)
    {
        printf("PushNum:Insufficient Memory!\n");
        exit(0);
    }
    if (stack->top + 1 == stack->base)  // 判断是否栈满
    {
        printf("PushNum:Stack is full!\n");
        exit(0);
    }

    (stack->top)++;
    (stack->data)[stack->top] = digit;
}

/* 运算符压栈 */
void PushOpr(dStack_t* stack, char ch)
{
    int opr = (int)ch;
    if (NULL == stack)
    {
        printf("PushOpr:Insufficient Memory!\n");
        exit(0);
    }
    if (stack->top + 1 == stack->base)  // 判断是否栈满
    {
        printf("PushOpr:Stack is full!\n");
        exit(0);
    }

    (stack->base)--;
    (stack->data)[stack->base] = opr;
}

/* 数字出栈 */
int PopNum(dStack_t* stack)
{
    int digit = 0;
    if (NULL == stack)
    {
        printf("PopNum:Insufficient Memory!\n");
        exit(0);
    }
    if (-1 == stack->top)     // 判断栈数据侧是否空
    {
        printf("PopNum:Stack is empty!\n");
        exit(0);
    }

    digit = (stack->data)[stack->top];
    (stack->data)[stack->top] = 0;    // 栈内存清零,可删除此行代码
    (stack->top)--;
    return digit;
}

/* 运算符出栈 */
char PopOpr(dStack_t* stack)
{
    char opr = 0;
    if (NULL == stack)
    {
        printf("PopOpr:Insufficient Memory!\n");
        exit(0);
    }
    if (DSTACK_SIZE == stack->base)  // 判断栈运算符侧是否空
    {
        printf("PopOpr:Stack is empty!\n");
        exit(0);
    }

    opr = (char)(stack->data)[stack->base];
    (stack->data)[stack->base] = 0;  // 栈内存清零,可删除
    (stack->base)++;
    return opr;
}

/* 取数据侧栈顶数字 */
int GetTopNum(dStack_t* stack)
{
    if (NULL == stack)
    {
        printf("GetTopNum:Insufficient Memory!\n");
        exit(0);
    }
    if (-1 == stack->top)            // 判断栈运算符侧是否空
    {
        printf("PopOpr:Stack is empty!\n");
        return 0;
    }

    return (stack->data)[stack->top];
}

/* 取运算符侧栈顶运算符 */
char GetTopOpr(dStack_t* stack)
{
    if (NULL == stack)
    {
        printf("GetTopOpr:Insufficient Memory!\n");
        exit(0);
    }
    if (DSTACK_SIZE == stack->base)  // 判断栈运算符侧是否空
    {
        printf("GetTopOpr:Stack is empty!\n");
        return 0;
    }

    return ((char)(stack->data)[stack->base]);
}

/* 判断输入字符是否运算符:运算符返回1,数字返回0,其他字符返回-1 */
int IsOpr(char ch)
{
    if ('+' == ch || '-' == ch || '*' == ch || '/' == ch
        || '(' == ch || ')' == ch || '=' == ch)
    {
        return 1;
    }
    else if (ch >= '0' && ch <= '9')
    {
        return 0;
    }
    else
    {
        return -1;
    }
}

/* 判断运算符的优先级 */
char Precede(char aOpr, char bOpr)
{
    switch (aOpr)
    {
    case '+':
    case '-':
    {
        if ('*' == bOpr || '/' == bOpr || '(' == bOpr)
        {
            return '<';
        }
        else
        {
            return '>';
        }
    }           // 使用return返回,故不加break语句
    case '*':
    case '/':
    {
        if ('(' == bOpr)
        {
            return '<';
        }
        else
        {
            return '>';
        }
    }
    case '(':
    {
        if (')' == bOpr)
        {
            return '=';
        }
        else
        {
            return '<';
        }
    }
    case ')':            // 不会出现这种情况
    {
        return '>';
    }
    case '=':
    {
        if ('=' == bOpr)
        {
            return '=';
        }
        else
        {
            return '<';
        }
    }
    default:
    {
        exit(0);
    }
    }
}


注:资料来源于网络,侵权联系删除。

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值