【数据结构C++】表达式求值(多位数)课程设计

news2024/12/27 13:56:51


📚博客主页:Zhui_Yi_
🔍:上期回顾:图

❤️感谢大家点赞👍🏻收藏⭐评论✍🏻,您的三连就是我持续更新的动力❤️
🎇追当今朝天骄,忆顾往昔豪杰。
在这里插入图片描述

文章目录

  • 前言
    • 问题描述
    • 基 本 要 求
    • 实 现 提 示
  • 一、摘要以及引言
    • 摘要
    • 引言
  • 二、系统设计
  • 三、关键算法与实现
    • 1.运算符处理
    • 2.表达式求值流程
  • 四、程序实现
  • 五、具体代码
    • 1.定义结构以及初始化
    • 2.简单的链栈操作
      • 判空
      • 入栈
      • 出栈
      • 取栈顶元素
      • 判断运算符是否有效
      • 将运算符转换
      • 判断运算符优先级
      • 进行运算
      • 进行运算
      • 完整代码
  • 总结
  • 切记切记,我给出代码缺少对括号匹配的信息,但代码是能直接运行的,需要你们自己写出来。

前言

本期呢,给大家带来的课程设计,简单给大家说一哈要求:

问题描述

任 何 一 个 表 达 式 都 是 由 操 作 数 (operand)、 运 算 符 (operator)和 界 限 符
(delimiter)组 成 的 。 其 中 , 操 作 数 可 以 是 常 量 , 也 可 以 是 变 量 ; 运 算 符 可 以 是 算
术 运 算 符 、关 系 运 算 符 和 逻 位 算 符 ;界 限 符 是 左 、右 括 号 和 标 志 表 达 式 结 束 的 结 束 符。
在 本 课 程 设 计 中 ,仅 讨 论 简 单 算 术 表 达 式 的 求 值 问 题 , 约 定 表 达 式 中 只 包 含 加 、减 、 乘 、 除 4 种运算, 所 有 的 运 算 对 象 均 为 简 单 变 量 , 表 达 式 的 结 束 符 为 “ =”。
要 求以 字 符 序 列 的 形 式 从 终 端 输 入 语 法 正 确 、不 含 变 量 的 整 数 表 达 式 。 利 用 已 知 的 运 算 符 优 先 关 系 , 实 现 对 算 术 表 达 式 的 求 值 。

基 本 要 求

这 是 一 个 利 用 栈 结 构 完 成 的 程 序 。为 了 实 现 运 算 符 优 先 算 法 ,需 使 用 两 个 工 作 栈 ,一 个 称 为 运 算 符 栈 (OPTR), 用 来 寄 存 运 算 符 ; 另 一 个 称 为 操 作 数 栈 (OPND), 用 来
寄 存 操 作 数 或 运 算 结 果 。 基 本 要 求 如 下 : (1) 表 达 式 中 只 包 含 加 、 减 、 乘 、 除 4
种 运 算 , 应 按 优 先 级 进 行 运 算 。
(2) 表 达 式 中 不 包 含 变 量 。
(3) 操 作 数 应 为 整 数
(4) 操 作 数 应 包 含 1 位 数 , 2 位 数 , 3 位 数 等 不 同 数 据 。
(5) 初 始 状态: 操作数栈(OPND)为空栈,表达式结束符“ =” 为 运 算 符 栈 (OPTR)的 栈 底 元 素 。

实 现 提 示

假 设 算 术 表 达 式 Expression 内 可 以 含 有 常 量 (0~9)和 二 元 运 算 符(+, -, *, /)。 实
现 以 下 操 作 : (1) ReadExpre(E): 对 以字符序列的形式输入语法正确的 中 缀表 达 式 并 构 造 表 达 式 E。
(2) EValuation(): 对 算 术 表 达 式 E 求 值 。 (3) Compare(c1,c2): 比 较 运 算 符
优 先 级 。
(4) Operate(a,optr,b):根 据 运 算 符 optr 进 行 操 作 数 a 和 b 的 运算 。
(5) 栈 的 相 关 操 作 ( 必 须 自 己 实 现 , 不 可 使 用 现 成 的 模 板 类 )。

一、摘要以及引言

摘要

本文介绍了一个利用链栈数据结构实现的简单中缀表达式求值程序。该程序能够接收用户输入的数学表达式,支持加减乘除四则运算及括号,以等号“=”作为输入结束标志,计算表达式的值并输出结果。本文详细阐述了程序的设计思路、核心算法及实现细节,旨在为初学者提供一个学习链栈应用和表达式求值原理的实践案例。

引言

在计算机科学领域,表达式求值是一项基本而重要的任务,广泛应用于编译器设计、计算器开发等多个场景。其中,中缀表达式是最自然的数学表达形式,但直接计算中缀表达式较为复杂。本文采用栈这一数据结构,设计并实现了一个程序,能够高效地将中缀表达式转换为后缀表达式(逆波兰表示法),进而计算其值。

二、系统设计

  • 本系统主要由以下几个部分组成:
  • 链栈结构:定义了两个链栈,OPTD用于存储操作数,OPTR用于存储运算符。
    表达式解析与计算:程序首先读取用户输入的中缀表达式,然后根据运算符优先级和括号规则,将表达式转换为便于计算的形式,并最终求得结果。
    用户交互:提供友好界面,用户输入表达式,以等号结束,程序显示计算结果,并询问是否继续进行新的计算。

三、关键算法与实现

1.运算符处理

  • 运算符入栈规则:程序通过Precede函数判断新读入的运算符与栈顶运算符的优先级,优先级较低的运算符先出栈计算。
    括号处理:遇到左括号入栈,遇到右括号则弹出栈顶运算符直到遇到左括号,处理括号内表达式。
    等号处理:等号既是输入结束标志,也作为特殊运算符处理,确保表达式正确结束。

2.表达式求值流程

  1. 初始化:初始化两个链栈。
  2. 读取输入:逐字符读取用户输入的表达式。
  3. 字符处理:对每个字符判断是否为运算符、数字或结束符号,进行相应处理。
  4. 运算符优先级判定与操作数计算:使用栈结构辅助计算,遵循运算符优先级规则。
  5. 输出结果:计算完成后,输出表达式的计算结果。

四、程序实现

本程序使用C++语言实现,主要采用了结构体定义链栈,通过自定义的链栈操作函数实现了数据的入栈、出栈等操作。calculate函数为核心,负责解析和计算表达式。通过一系列条件判断和循环结构,实现了对中缀表达式的有效处理。此外,程序还包含用户交互环节,提高了用户体验。

五、具体代码

1.定义结构以及初始化

// 链栈节点结构
struct Node {
    double data;
    Node* next;
};

// 链栈结构
struct LinkStack {
    Node* top;
    int size;
};

// 初始化链栈
LinkStack* InitLinkStack() {
    LinkStack* stack = new LinkStack;
    stack->top = nullptr;
    stack->size = 0;
    return stack;
}

2.简单的链栈操作

判空

bool IsEmpty(LinkStack* stack) {
    return stack->top == nullptr;
}

入栈

// 入栈操作
void Push(LinkStack* stack, double value) {
    Node* node = new Node;
    node->data = value;
    node->next = stack->top;
    stack->top = node;
    stack->size++;
}

出栈

double Pop(LinkStack* stack) {
    if (IsEmpty(stack)) {
        throw runtime_error("栈是空的!");
    }
    double value = stack->top->data;
    Node* temp = stack->top;
    stack->top = stack->top->next;
    delete temp;
    stack->size--;
    return value;
}

取栈顶元素

// 获取栈顶元素
double GetTop(LinkStack* stack) {
    if (IsEmpty(stack)) {
        throw runtime_error("栈是空的!");
    }
    return stack->top->data;
}

判断运算符是否有效

运算符分为+、-、*、/、=,即:

bool In(char c) {
    if (c == '(' || c == ')' || c == '+' || c == '-' || c == '*' || c == '/' || c == '=')
        return true;
    return false;
}

将运算符转换

int intdata(char c) {
    switch (c) {
    case '+': return 0;
    case '-': return 1;
    case '*': return 2;
    case '/': return 3;
    case '(': return 4;
    case ')': return 5;
    case '=': return 6; 
    default: break;
    }
}

判断运算符优先级

在这里插入图片描述
根据这张图片进行建立二维数组。

char Precede(char c1, char c2) {
    int a, b;
    char table[7][7] = {
        '>','>','<','<','<','>','>',
        '>','>','<','<','<','>','>',
        '>','>','>','>','<','>','>',
        '>','>','>','>','<','>','>',
        '<','<','<','<','<','=','0',
        '>','>','>','>','0','>','>',
        '<','<','<','<','<','0','=',
    };
    a = intdata(c1); b = intdata(c2);
    return table[a][b];
}

进行运算

double operate(double a, char c, double b) {
    if (c == '+') return (a + b);
    else if (c == '-') return (a - b);
    else if (c == '*') return (a * b);
    else if (c == '/') {
        if (b == 0) return (flag = 1);
        else return (a / b);
    }
}

进行运算

double calculate() {
    char ch, tempc;
    double x, y, temp, count = 0;
    Push(OPTR, '='); 
    cin >> ch;
    while (ch != '=' || GetTop(OPTR) != '=') { 
        if (!In(ch)) {
            if (count != 0) {
                temp = GetTop(OPTD); Pop(OPTD);
                temp = (double)(temp * 10 + ch - '0');
                Push(OPTD, temp);
                cin >> ch;
            }
            else {
                temp = (double)(ch - '0');
                Push(OPTD, temp);
                count++;
                cin >> ch;
            }
        }
        else {
            count = 0;
            switch (Precede(GetTop(OPTR), ch)) {
            case '<':
                Push(OPTR, ch);
                cin >> ch;
                break;
            case '>':
                tempc = GetTop(OPTR); Pop(OPTR);
                y = GetTop(OPTD); Pop(OPTD);
                x = GetTop(OPTD); Pop(OPTD);
                Push(OPTD, operate(x, tempc, y));
                break;
            case '=':
                tempc = GetTop(OPTR); Pop(OPTR);
                cin >> ch;
                break;
            default:
                break;
            }
        }
    }
    return GetTop(OPTD);
}

完整代码

#include <iostream>
#include <string>

using namespace std;

// 链栈节点结构
struct Node {
    double data;
    Node* next;
};

// 链栈结构
struct LinkStack {
    Node* top;
    int size;
};

// 初始化链栈
LinkStack* InitLinkStack() {
    LinkStack* stack = new LinkStack;
    stack->top = nullptr;
    stack->size = 0;
    return stack;
}

// 判断栈是否为空
bool IsEmpty(LinkStack* stack) {
    return stack->top == nullptr;
}

// 入栈操作
void Push(LinkStack* stack, double value) {
    Node* node = new Node;
    node->data = value;
    node->next = stack->top;
    stack->top = node;
    stack->size++;
}

// 出栈操作
double Pop(LinkStack* stack) {
    if (IsEmpty(stack)) {
        throw runtime_error("栈是空的!");
    }
    double value = stack->top->data;
    Node* temp = stack->top;
    stack->top = stack->top->next;
    delete temp;
    stack->size--;
    return value;
}

// 获取栈顶元素
double GetTop(LinkStack* stack) {
    if (IsEmpty(stack)) {
        throw runtime_error("栈是空的!");
    }
    return stack->top->data;
}

// 全局链栈
LinkStack* OPTD = InitLinkStack();
LinkStack* OPTR = InitLinkStack();
int flag = 0;

// 判断字符是否为运算符
bool In(char c) {
    if (c == '(' || c == ')' || c == '+' || c == '-' || c == '*' || c == '/' || c == '=')
        return true;
    return false;
}

// 将运算符转换为序号
int intdata(char c) {
    switch (c) {
    case '+': return 0;
    case '-': return 1;
    case '*': return 2;
    case '/': return 3;
    case '(': return 4;
    case ')': return 5;
    case '=': return 6; // 修改这里,添加'='的序号
    default: break;
    }
}

// 判定运算符优先级
char Precede(char c1, char c2) {
    int a, b;
    char table[7][7] = {
        '>','>','<','<','<','>','>',
        '>','>','<','<','<','>','>',
        '>','>','>','>','<','>','>',
        '>','>','>','>','<','>','>',
        '<','<','<','<','<','=','0',
        '>','>','>','>','0','>','>',
        '<','<','<','<','<','0','=',
    };
    a = intdata(c1); b = intdata(c2);
    return table[a][b];
}

// 执行运算
double operate(double a, char c, double b) {
    if (c == '+') return (a + b);
    else if (c == '-') return (a - b);
    else if (c == '*') return (a * b);
    else if (c == '/') {
        if (b == 0) return (flag = 1);
        else return (a / b);
    }
}

// 表达式求值
double calculate() {
    char ch, tempc;
    double x, y, temp, count = 0;
    Push(OPTR, '='); 
    cin >> ch;
    while (ch != '=' || GetTop(OPTR) != '=') { 
        if (!In(ch)) {
            if (count != 0) {
                temp = GetTop(OPTD); Pop(OPTD);
                temp = (double)(temp * 10 + ch - '0');
                Push(OPTD, temp);
                cin >> ch;
            }
            else {
                temp = (double)(ch - '0');
                Push(OPTD, temp);
                count++;
                cin >> ch;
            }
        }
        else {
            count = 0;
            switch (Precede(GetTop(OPTR), ch)) {
            case '<':
                Push(OPTR, ch);
                cin >> ch;
                break;
            case '>':
                tempc = GetTop(OPTR); Pop(OPTR);
                y = GetTop(OPTD); Pop(OPTD);
                x = GetTop(OPTD); Pop(OPTD);
                Push(OPTD, operate(x, tempc, y));
                break;
            case '=':
                tempc = GetTop(OPTR); Pop(OPTR);
                cin >> ch;
                break;
            default:
                break;
            }
        }
    }
    return GetTop(OPTD);
}

// 菜单函数
void menu() {
    puts("\n=========================\n");
    puts("       表达式求值");
    puts("\n=========================\n");
}

// 主函数
int main() {
    menu();
    double answer, trueValue = 1;
    while (trueValue) {
        cout << "\n请输入表达式,以等号(=)结束:"; 
        answer = calculate();
        if (flag == 1) {
            cout << "分母不能为0哦!" << endl;
            flag = 0;
        }
        else
            cout << "表达式的值为:" << answer << endl;
        cout << "按0可结束程序,继续请按1:";
        cin >> trueValue;
    }
    return 0;
}

在这里插入图片描述

总结

本文通过设计链栈数据结构和实现相应的算法,成功开发了一个能够处理中缀表达式的程序。该程序不仅能够正确计算表达式的值,还具备良好的用户交互体验,适合教学和初步编程实践。未来的工作可以考虑扩展程序功能,支持更多类型的运算符和更复杂的表达式结构。

切记切记,我给出代码缺少对括号匹配的信息,但代码是能直接运行的,需要你们自己写出来。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1837390.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

使用Ollama+OpenWebUI本地部署阿里通义千问Qwen2 AI大模型

&#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f916;AI大模型部署与应用专栏&#xff1a;点击&#xff01; &#x1f916;Ollama部署LLM专栏&#xff1a;点击&#xff01; ⏰️创作时间&#xff1a;2024年6月17日22点50分 &#x1f004;️文章质量&#xff…

函数(下) C语言

函数下 嵌套调用和链式访问1. 嵌套调用2. 链式访问 函数的声明和定义1. 单个文件2. 多个文件3. static 和 extern3.1 static 嵌套调用和链式访问 1. 嵌套调用 嵌套调用就是函数之间的互相调用&#xff0c;每个函数就像⼀个乐高零件&#xff0c;正是因为多个乐高的零件互相无缝…

MacOS - 启动台多了个『卸载 Adobe Photoshop』

问题描述 今天安装好了 Adobe Ps&#xff0c;但是发现启动台多了个『卸载 Adobe Photoshop』强迫症又犯了&#xff0c;想把它干掉&#xff01; 解决方案 打开访达 - 前往 - 资源库&#xff0c;搜索要卸载的名字就可以看到&#xff0c;然后移除到垃圾筐

17. 一个I/O项目:构建命令行程序(下)

目录 五、采用测试驱动开发完善库的功能5.1 编写失败测试用例5.2 编写成功测试用例5.3 在run函数中打印搜索到的行 六、添加大小写不敏感功能七、将错误信息输出到标准错误八、附录完整代码 五、采用测试驱动开发完善库的功能 5.1 编写失败测试用例 在lib.rs中写一个简单的se…

爱死了,4款逆天IOS App推荐!

河马喝水提醒 「河马喝水提醒」是一款生活小助手应用&#xff0c;旨在帮助用户建立并维持定时喝水的良好习惯。该应用不仅是一个提醒闹钟&#xff0c;更是健康生活的贴心伙伴。它每天定时推送提醒&#xff0c;帮助用户在繁忙的日常中不忘补充水分。此外&#xff0c;该应用还提供…

jenkins中配置参数化,并在python脚本接收参数实现参数化执行

在公司内进行Monkey测试脚本集成jenkins时&#xff0c;因为需要指定公司内不同的app进行测试。那么可以有两种方法解决该问题&#xff0c;要么创建多个脚本文件&#xff0c;多个jenkins jobs&#xff0c;进行构建。要么可以在配置job时通过传参数的方式&#xff0c;在python脚本…

Facebook视角下的文化多样性:全球社交的聚合

在当今数字化时代&#xff0c;社交媒体已经成为连接全球各地人们的重要平台之一。而在这众多平台中&#xff0c;Facebook无疑是其中的佼佼者&#xff0c;不仅仅是一个社交网络&#xff0c;更是一个涵盖了丰富文化多样性的全球社交聚合地。本文将深入探讨Facebook在促进文化多样…

[python] matplotlib.pyplot 绘制高宽不同、多行多列子视图

假如我们想要绘制这样的效果&#xff1a; 方式1&#xff1a; # -*- coding: utf-8 -*- import matplotlib.pyplot as plt import numpy as np# 声明一个GridSpec对象实例&#xff0c;创建的是6行2列的图像布局。 grid plt.GridSpec(nrows6, ncols2, wspace0.2, hspace0.2)# 设…

京东618 :AI总裁数字人、京东Apple Vision Pro版亮相

2004年6月18日&#xff0c;刚刚转型电商才半年的京东&#xff0c;用最互联网的方式为忠实粉丝打造了一场价格降到“难以置信”的店庆促销活动&#xff0c;这场促销活动还有一个很具有当年网络小说特质的名字——“月黑风高”。 2024年京东618&#xff0c;早已成为一场亿万消费…

【只是查漏补缺】关于动力节点2024版java新课程

反编译命令 javap进行反编译操作&#xff0c;例如&#xff1a;javap Test&#xff1b;使用jd-gui.exe来实现反编译。 二进制数据是采用0和1来表示&#xff0c;则换算单位肯定为2的n次方&#xff0c;而2的10次方恰好等于1024&#xff0c;所以就使用了1024来作文文件存储的换算单…

Erlang程序设计[Part1-Part2 chapter4]

前言&#xff1a; 环境安装 Erlang Shell&#xff0c;CSDN搜教程 Erlang Shell实操 启动 erl Erlang Shell以表达式为执行单位&#xff1f; 结束标志 .加上回车 Part1 为何用 Erlang chapter 1 什么是并发 并发vs并行 并发 单核cpu运行多个进程 一次运行一个 并行 多…

批量导出兜底回复对话,迭代优化聊天机器人 | Chatopera 云服务

持续优化知识库 聊天机器人的知识库&#xff0c;对话技能&#xff0c;需要长期的优化。这是因为&#xff0c;一方面&#xff0c;初期上线的机器人所依赖的数据量通常有限&#xff1b;另一方面&#xff0c;市场不断变化&#xff0c;客户产品新的问题。 上线聊天机器人的目的之…

MyBatis Plus Generator代码生成

一、MyBatis Plus Generator MyBatis Plus是一个功能强大的持久层框架&#xff0c;它简化了MyBatis的使用&#xff0c;提供了许多便捷的功能。其中&#xff0c;MyBatis Plus Generator是一个强大的代码生成器&#xff0c;可以帮助我们快速地根据数据库表结构生成对应的实体类、…

怎么控制多个存储设备的访问权限?数据安全存储方案来了

数据安全存储是指将数据以安全的方式存储在存储系统中&#xff0c;以确保数据的机密性、完整性和可用性。要控制数据安全存储的权限以保障安全&#xff0c;可以采取以下措施&#xff1a; 访问控制列表&#xff08;ACLs&#xff09;&#xff1a;使用ACLs来定义对存储数据的访问权…

丹麦海外媒体报道:媒体投放发稿助力企业在海外扭转战局

大舍传媒 丹麦海外媒体报道中&#xff0c;大舍传媒作为一家专业的媒体投放公司&#xff0c;正发挥着重要作用&#xff0c;帮助企业在海外扭转战局。作为丹麦领先的媒体投放机构&#xff0c;他们为企业提供了全方位的品牌传播服务&#xff0c;帮助企业在海外市场取得成功。 大舍…

MySQL 架构

本篇主要介绍一下MySQL的架构 目录 一、整体架构 二、连接层 网络端口 连接管理线程 三、服务层 NoSQL接口与SQL接口 Parser&#xff08;语法分析器&#xff09; Optimizer&#xff08;查询优化器&#xff09; Cache & Buffers(缓存&#xff09; 四、存储引擎层…

可复用验证的测试用例 5大编写技巧

编写可复用验证的测试用例&#xff0c;节省了编写新测试用例的时间和资源&#xff0c;提高了测试效率和项目质量&#xff0c;减少错误修复成本&#xff0c;有利于实现较高的投入产出比。缺乏可复用的测试用例会导致测试团队不断重复创建相似的测试场景&#xff0c;消耗大量时间…

CleanMyMac中文版2024破解版安装包下载最新官方免费激活码

CleanMyMac中文版&#xff0c;让你的电脑焕然一新&#xff01; 大家好&#xff0c;今天我要给大家推荐一款神奇的软件——CleanMyMac中文版。作为一个长期使用Mac的用户&#xff0c;我一直在寻找一款能够彻底清理电脑垃圾和优化系统的工具&#xff0c;而CleanMyMac正是我心心念…

封装音视频编解码和渲染的动态链接库编译和测试

1.动态链接库的编译 生成了以下几个文件 我们把生成的lib文件复制到lib文件夹中 其余三个文件不变动 2.进行测试看是否可以用生成的xcodec.lib库文件里的接口函数 以上是重新创建的新项目&#xff0c;导入了xcodec.lib&#xff0c;其他配置同以前项目 库测试结果 运行显示我们…

优思学院|精益生产10大工具全解析

精益生产是一种管理哲学&#xff0c;其核心思想是通过消除浪费、持续改进和最大化价值来提高企业效率和效益。本文将详细解析精益生产的10大工具&#xff0c;帮助企业更好地理解和实施精益生产&#xff0c;以实现卓越的经营绩效。 一、价值流图 (Value Stream Mapping) 前言 …