目录

目的描述:

算法的基本思想:

错误点:

完整代码:

1.输入输出

2.栈操作函数包(数组堆栈.h)

3.实现表达式求值函数包(表达式求值.c)

4.测试输出:


目的描述:

算符优先算法要实现的是,根据运算优先关系来对一个表达式求值,假如说要计算:

4+2*3-10/5

运算的顺序例如:

4+2*3-10/5  =  4+6-10/5  =  10-10/5  =  10-2  =  8 (开始不是很理解的话可以继续往下看)

算法的基本思想:

为实现算符优先算法,可以使用两个工作栈。一个称做 OPTR,用以寄存运算符;另一个称做 OPND,用以寄存操作数或运算结果。

(1)首先置操作数栈为空栈,表达式起始符“#”为运算符栈的栈底元素;
(2) 依次读人表达式中每个字符,若是操作数则进 OPND栈,若是运算符则和OPTR 栈的栈顶运算符比较优先权后作相应操作,直至整个表达式求值完毕(即 OPTR栈的栈顶元素和当前读人的字符均为“#”)

(3)在这里分别定义了两套对栈进行基本操作的函数,只有函数名改变其他均相同。这样做的原因是,在对寄存运算符时,需要字符栈;而寄存操作数或运算结果时,字符栈无法满足多位数的操作,所以这里采用数字栈(后来看到了另一位作者的文章,两个栈都采用数字栈也可以实现,并且会大大减少代码数量,原理就是在存放操作符的时候,将会转化成ASCII码的形式存入栈中)

(4)这里是两个最近的运算符的优先级关系表:(用来参考着写计算算符优先级的函数)

(空白的地方是不可能存在的合法运算符关系,可忽略)

(5)通过利用对栈的基本操作函数,对两个栈进行操作,按步骤分解可以参考下表

错误点:

(记录一下自己遇到的错误)

(1)就是关于在寄存操作数或运算结果时开始没有考虑到有多位数的情况,我对多位数的处理是,设定了一个flag判断,如果连续getchar()得到的都是数字,就令flag=1;如果遇到了运算符,就令flag=0。

(2)在计算每一步结果的函数 Operate(double a, char theta, double b)里,当这是的操作是’-‘或者’/‘时,要注意a,b的顺序,因为栈的特点是LIFO(last in first out),所以除数和被除数,减数和被减数就会颠倒过来,要记得写成反的。

(3)记得判断输入getchar()为换行符’\n'时要跳出循环的判断。

完整代码:

1.输入输出

输入:一个只含有‘+’,‘-’,‘/’,‘*’,‘#’运算符和数字的运算表达式,中间没有空格,结尾以#结束

输出:一个整数计算结果

2.栈操作函数包(数组堆栈.h)

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define STACK_INIT_SIZE 100
#define STACKINCREMENT 10
typedef char Elemtype1;//提供给存储运算符的栈使用
typedef double Elemtype2;//提供给存储操作数的栈使用typedef struct {Elemtype1 *data;int top;//栈顶指针,这里用int类型表示指针的下标int stacksize;
} SqStack1;
Elemtype1 Pop1(SqStack1 *s);typedef struct {Elemtype2 *data;int top;//栈顶指针,这里用int类型表示指针的下标int stacksize;
} SqStack2;
Elemtype2 Pop2(SqStack2 *s);SqStack1 InitStack1() {//空栈构造函数SqStack1 s;s.data = (Elemtype1 *)malloc(STACK_INIT_SIZE * sizeof(Elemtype1));s.top = -1; //表示栈空s.stacksize = STACK_INIT_SIZE;if (s.data != NULL){}elseprintf("Init error!\n");return s;
}void DestroyStack1(SqStack1 *s) {//销毁栈函数free(s->data);
}int StackEmpty1(SqStack1 *s) {//判断是否为空栈,是返回1,否 返回0if (s->top == -1)return 1;elsereturn 0;
}void ClearStack1(SqStack1 *s) {//清除栈while (StackEmpty1(s) != 1) {Pop1(s);}
}void Push1(SqStack1 *s, Elemtype1 e) {//添加元素入栈if (s->top >= s->stacksize) {s->data = (Elemtype1 *)malloc((STACK_INIT_SIZE + STACKINCREMENT) * sizeof(Elemtype1));s->stacksize += STACKINCREMENT;if (s->data != NULL) {}elseprintf("Push error!\n");} else {s->top++;s->data[s->top] = e;}
}Elemtype1 Pop1(SqStack1 *s) {//删除栈顶元素并返回其值,否则返回ERRORif (StackEmpty1(s) != 1 && s->top >= 0) {Elemtype1 e = s->data[s->top];s->top--;return e;}printf("Pop error!\n");
}int StackLength1(SqStack1 *s) {//返回栈的长度int len = 0, temp = s->top;while (temp >= 0) {len++;temp--;}return len;
}Elemtype1 GetTop1(SqStack1 *s) {//返回栈顶元素if (StackEmpty1(s) != 1) {return s->data[s->top];} elseprintf("GetTop error!\n");
}int StackTraverse1(SqStack1 *s) {//从栈底向栈顶访问每个元素if (StackEmpty1(s) == 1) {printf("栈为空!\n");return 0;}int temp = 0;while (temp <= s->top) {printf("%c ", s->data[temp]);temp++;}return 1;
}//以下是对第二组堆栈操作的定义*************************************************
SqStack2 InitStack2() {//空栈构造函数SqStack2 s;s.data = (Elemtype2 *)malloc(STACK_INIT_SIZE * sizeof(Elemtype2));s.top = -1; //表示栈空s.stacksize = STACK_INIT_SIZE;if (s.data != NULL){}elseprintf("Init error!\n");return s;
}void DestroyStack2(SqStack2 *s) {//销毁栈函数free(s->data);
}int StackEmpty2(SqStack2 *s) {//判断是否为空栈,是返回1,否 返回0if (s->top == -1)return 1;elsereturn 0;
}void ClearStack2(SqStack2 *s) {//清除栈while (StackEmpty2(s) != 1) {Pop2(s);}
}void Push2(SqStack2 *s, Elemtype2 e) {//添加元素入栈if (s->top >= s->stacksize) {s->data = (Elemtype2 *)malloc((STACK_INIT_SIZE + STACKINCREMENT) * sizeof(Elemtype2));s->stacksize += STACKINCREMENT;if (s->data != NULL) {}elseprintf("Push error!\n");} else {s->top++;s->data[s->top] = e;}
}Elemtype2 Pop2(SqStack2 *s) {//删除栈顶元素并返回其值,否则返回ERRORif (StackEmpty2(s) != 1 && s->top >= 0) {Elemtype2 e = s->data[s->top];s->top--;return e;}printf("Pop error!\n");
}int StackLength2(SqStack2 *s) {//返回栈的长度int len = 0, temp = s->top;while (temp >= 0) {len++;temp--;}return len;
}Elemtype2 GetTop2(SqStack2 *s) {//返回栈顶元素if (StackEmpty2(s) != 1) {return s->data[s->top];} elseprintf("GetTop error!\n");
}int StackTraverse2(SqStack2 *s) {//从栈底向栈顶访问每个元素if (StackEmpty2(s) == 1) {printf("栈为空!\n");return 0;}int temp = 0;while (temp <= s->top) {printf("%c ", s->data[temp]);temp++;}return 1;
}

3.实现表达式求值函数包(表达式求值.c)

#include "数组堆栈.h"
double EvaluateExpression();
int isAccepted(char);
char Precede(char, char);
double Operate(double a, char theta, double b);int main() {printf("请输入一个表达式:");double result;result = EvaluateExpression();printf("表达式的计算结果是:%0.f", result);return 0;
}int flag = 0; //如果在操作数栈有连续数字的输入,则设flag=1标记,用于多位数的计算
double EvaluateExpression() {SqStack1 OPTR;SqStack2 OPND;char e, theta;double a, b;e = getchar();OPTR = InitStack1(); //运算符栈Push1(&OPTR, '#');OPND = InitStack2(); //操作数或运算结果栈while (GetTop1(&OPTR) != '#' || e != '#') {if (e == '\n')break;if (isAccepted(e) == 1) { //如果字符是数字e = e - '0';if (flag == 1) { //是多位数double temp = Pop2(&OPND);temp = temp * 10 + e;Push2(&OPND, temp);} else {Push2(&OPND, e);flag = 1;}e = getchar();} else {flag = 0;switch (Precede(GetTop1(&OPTR), e)) {case '<'://栈顶元素优先级低,压入栈Push1(&OPTR, e);e = getchar();break;case '>'://新运算符优先级低,将前一个运算符弹出进行计算a = Pop2(&OPND);theta = Pop1(&OPTR);b = Pop2(&OPND); //abc//将计算结果再次压入运算结果栈Push2(&OPND, Operate(a, theta, b));//注意这里不用再重新获取e的值break;case '=':Pop1(&OPTR);//将剩下的一半括号弹出e = getchar();break;}}}return GetTop2(&OPND);//返回计算结果}int isAccepted(char e) { //如果字符是数字,返回1;字符是运算符,返回2;否则返回0char number[15] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};char calculate[15] = {'+', '-', '(', ')', '*', '#', '/'};for (int i = 0; i <= 9; i++) {if (number[i] == e)return 1;}for (int i = 0; i <= 6; i++) {if (calculate[i] == e)return 2;}return 0;
}char Precede(char a, char b) {if (b == '+' || b == '-') {if (a == '(' || a == '#')return '<';elsereturn '>';} else if (b == '*' || b == '/') {if (a == '*' || a == '/' || a == ')')return '>';elsereturn '<';} else if (b == '(')return '<';else if (b == ')') {if (a != '(')return '>';elsereturn '=';} else if (b == '#') {if (a != '#')return '>';elsereturn '=';}}double Operate(double a, char theta, double b) {if (b == 0) {printf("Conflicts with calculation rules!\n");return;}if (theta == '+')return a + b;else if (theta == '-')return b - a;//因为栈先弹出减数,所以要交换顺序else if (theta == '*')return a * b;else if (theta == '/')return b / a;//因为栈先弹出除数,所以要交换顺序
}

4.测试输出:

有错误欢迎指正喔!!\\(^-^)//

C语言-用栈实现表达式求值相关推荐

  1. 《Algorithms》—— Dijkstra 的双栈算术表达式求值算法

    想当年学数据结构的时候,一直觉得这个是我一辈子都搞不懂的一个东西.现在看看...还挺简单的... 重点在于如何解析由括号.运算符和数字组成的字符串,并按照正确的顺序完成各种初级算术操作.利用了两个栈( ...

  2. 顺序栈实现表达式求值(C语言实现)【栈】

    原理说明 代码实现 原理说明 表达式求值一定会出现表达式中运算符的优先级问题. 运算规则: 先乘除,后加减: 从左算到右: 先括号内,后括号外: 运算符优先表: 上面表格中有一些比较特殊的位置: ① ...

  3. 栈在表达式求值中的应用

    大家熟悉的算数表达式 表达式求值是程序设计语言编译中一个最基本的问题,它的实现是栈应用的一个典型范例. 波兰数学家的灵感 中缀.后缀.前缀表达式 中缀表达式不仅依赖运算符的优先级,而且还要处理括号. ...

  4. 栈 -- 顺序栈、链式栈的实现 及其应用(函数栈,表达式求值,括号匹配)

    文章目录 实现 顺序栈实现 链式栈实现 应用 函数栈 的应用 表达式求值中 的应用 括号匹配中 的应用 我们使用浏览器的时候经常会用到前进.后退功能. 依次访问完一串页面 a – b – c之后点击后 ...

  5. 【数据结构】用栈解决表达式求值问题

    题目:求4+4/2-9*3的值: 思路: ①:用一个字符型数组存放了表达式<4+4/2-9*3>: 1 char val[9] = {'4','+','4','/','2','-','9' ...

  6. 栈(模拟栈,表达式求值)

    模拟栈 #include<iostream>using namespace std;const int N=100010; int stk[N],tt;//向站内插入元素 void pus ...

  7. C++栈实现表达式求值

    转载:https://blog.csdn.net/qq_40475529/article/details/79661475,方便以后查看(嘿嘿)

  8. c语言求不定式的最大值,C语言之四则运算表达式求值(链栈)—支持浮点型数据,负数, 整型数据运算...

    运算符间的优先级关系: 链栈结构体定义: 数据域使用字符串长度为20的字符数组(故需要注意判断读取的字符串是运算符还是数值) 可支持浮点型数据,负数, 整型数据的运算 float EvaluateEx ...

  9. python数据结构和算法 时间复杂度分析 乱序单词检测 线性数据结构 栈stack 字符匹配 表达式求值 queue队列 链表 递归 动态规划 排序和搜索 树 图

    python数据结构和算法 参考 本文github 计算机科学是解决问题的研究.计算机科学使用抽象作为表示过程和数据的工具.抽象的数据类型允许程序员通过隐藏数据的细节来管理问题领域的复杂性.Pytho ...

最新文章

  1. SAP MM PR单据中采购组为空带来的问题
  2. 在一个夜黑风高的夜晚,坐在教室里学多线程
  3. echarts Cannot read property ‘getAttribute‘ of null 问题的解决方法
  4. Duilib教程-HelloDuilib及DuiDesigner的简单使用
  5. java filechannel api_FileChannel
  6. PLSQL登录报错ORA-12154
  7. 怎样修改t3服务器地址,怎样修改t3服务器地址
  8. CTFHUB《Web-信息泄露-备份文件下载》网站源码,
  9. SSM框架笔记08:初探Spring——采用配置类与注解方式
  10. 【Redis】redis 主从复制
  11. document.write vs document.getElementById
  12. android 课堂讨论内容,Android端课堂交互应用研究与实现
  13. gulp编译html中的less,使用插件less-plugin-functions让gulp-less支持自定义函数
  14. CC2530无线点灯
  15. 使用python3编写冒险岛079登录器
  16. 21天学通C语言-学习笔记(1)
  17. web打印时,各种页面样式设置
  18. 基于java+jsp的户籍管理系统
  19. 整理:状态机的编程思想
  20. CDN - 原理解析

热门文章

  1. 微信小程序之首页轮播图片自适应高度
  2. oracle删除字段约束条件,Oracle 数据库中关于对表字段约束的操作(设置、删除、查询)...
  3. 10分钟搞定Java带token验证的注册登录
  4. oracle中distinct和count函数组合使用
  5. STM32驱动直流电机(一)驱动电路的介绍
  6. 自动化设备数据采集系统优势
  7. 用html做七巧板的方法,七巧板制作教程 七巧板的制作方法
  8. 遇到不同网段互相访问的一些问题的总结
  9. mysql 计算近30天总金额_计算月嫂每天工资,应该用总工资除以30天还是26天?-免费法律咨询...
  10. [转贴]国内计算机类学术期刊投稿指南