运算符间的优先级关系:

链栈结构体定义:

数据域使用字符串长度为20的字符数组(故需要注意判断读取的字符串是运算符还是数值)

可支持浮点型数据,负数, 整型数据的运算

float EvaluateExpression() 函数实现步骤:

1)初始化OPTR栈和OPND栈,将表达式起始符 “#” 压入OPTR栈。

2)扫描表达式,读入第一个字符串str,如果表达式没有扫描完毕至 "#" 或压入OPTR的栈顶元素不为 "#" 时,则循环执行以下操作:

  ——>使用  str_to_float() 函数判断输入的字符串str是否是运算符

    ——>如果str不是运算符,则压入OPND栈,读取下一个字符串str

    ——>如果字符串str是运算符,使用 Precede() 函数获取OPTR栈顶元素的运算符和字符串str的运算符的优先级:

      ——>若是 ‘<’ ,则字符串str压入OPTR栈,读入下一个字符串str

      ——>若是 ‘>’ ,则弹出OPTR栈顶的运算符字符串,从OPND栈弹出两个数值字符串,使用 Operate() 函数对两个字符串进行运算,将得到的浮点型运算结果使用  float_to_str() 函数转换成字符串型数据,压入OPND栈

      ——>若是 ‘=’ ,则OPTR的栈顶元素是 "(" 且 str 是 ")" ,这时弹出OPTR栈顶的 "(" ,相当于括号匹配成功,然后读入下一字符串str

3)OPND栈顶元素记为表达式求值结果,输出运算结果。

实现代码(.cpp后缀文件)

 #include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h> #define inf float(0x3f3f3f3f)
#define MAXSIZE 100 char priority[] = {'+', '-', '*', '/', '(', ')', '#'}; char priority_relationship[][] = {
{'>', '>', '<', '<', '<', '>', '>'},
{'>', '>', '<', '<', '<', '>', '>'},
{'>', '>', '>', '>', '<', '>', '>'},
{'>', '>', '>', '>', '<', '>', '>'},
{'<', '<', '<', '<', '<', '=', ' '},
{'>', '>', '>', '>', ' ', '>', '>'},
{'<', '<', '<', '<', '<', ' ', '='}
}; // 各个运算符之间的优先级关系 int get_index(char str[])
{// 获取相应运算符的索引
for(int i = ; i < ; i++)
{
if(str[] == priority[i]) return i;
}
printf("未找到匹配的字符\n");
} char Precede(char inside_data[], char input_data[])
{// 获取两个运算符之间的优先级关系
int inside_index = get_index(inside_data);
int input_index = get_index(input_data); return priority_relationship[inside_index][input_index];
} typedef struct StackNode
{
char data[MAXSIZE]; // 压入栈里面的数据都是字符型,在进行运行时,记得将字符型数字转换为浮点型数字
struct StackNode *next;
}StackNode, *LinkStack; void InitStack(LinkStack &S)
{// 构造一个空栈S,栈顶指针置空
S = NULL;
} void Push(LinkStack &S, char data[])
{// 在栈顶插入元素data
StackNode *p; p = (StackNode *)malloc(sizeof(StackNode)); // 生成新的结点
strcpy(p->data, data); // 将新结点的数据域置为data
p->next = S; // 将新结点插入栈顶
S = p; // 修改栈顶指针为p
} char *Pop(LinkStack &S)
{// 删除S的栈顶元素, 用data返回其值
char data[MAXSIZE];
if(S == NULL) printf("错误!!!\n栈为空, 无法执行删除命令...");
else
{
StackNode *p; strcpy(data, S->data); // 将栈顶元素赋给data
p = S; // 用p临时保存栈顶元素的空间,以备释放
S = S->next; //修改栈顶指针
free(p); // 释放原栈顶元素的空间
return data;
}
} char *GetTop(LinkStack &S)
{// 获取栈顶元素
if(S != NULL)
return S->data;
else
{
printf("错误!!!\n栈顶为空");
return "";
}
} float str_to_float(char *str)
{// 将字符串数据转换成浮点型数据
float num = ;
int state_1 = ; // 用于判断是否读取到小数点的状态值, 0代表还没有读取到
int state_2 = ; //用于判断是否读取到负号的状态值, 0代表还没有读取到
while(( *str != '\0' && *str >= '' && *str <= '') || *str == '.' || (*str == '-' && *(str + ) != '\0'))
{// 注意判断小数点和负号
if(*str == '.') state_1 = ; // 当读取到小数点的时候, 状态值state_1赋值为1
else if(*str == '-') state_2 = ; // 当读取到负号的时候, 状态值state_2赋值为1
else
{
if(state_1 == ) num = num * + (*str - '');
else
{
num += (*str - '') * pow(0.1, state_1);
state_1++;
}
}
str++;
}
if(*str != '\0') return inf;
else if(state_2 == )
{
return num * -;
}
else return num;
} char *float_to_str(float num)
{// 将浮点型数据装换成字符串数据,保留浮点型数据小数点后4位的值
char str[MAXSIZE];
sprintf(str, "%.4f", num); // 保留小数点后4位
return str;
} float Operate(char a[], char theta[], char b[])
{//执行运算
float a_num = str_to_float(a);
float b_num = str_to_float(b); if(theta[] == '+') return a_num + b_num;
else if(theta[] == '-') return a_num - b_num;
else if(theta[] == '*') return a_num * b_num;
else if(theta[] == '/') return a_num / b_num;
else printf("错误!!!\n无该运算符");
} void EvaluateExpression()
{
StackNode *OPND, *OPTR;
char str[MAXSIZE];
char theta[MAXSIZE];
char a[MAXSIZE];
char b[MAXSIZE]; InitStack(OPND); // 初始化栈 OPND
InitStack(OPTR); // 初始化栈 OPTR
Push(OPTR, "#"); // 将 "#" 压入栈OPTR printf("请输入算术表达式(支持负数,浮点型数据),每个值用空格隔开输入,并以#结束\n");
scanf("%s", str);
while(str[] != '#' || GetTop(OPTR)[] != '#')
{
if(str_to_float(str) != inf)
{ // 如果str不是运算符,则压入OPND栈,读取下一个字符串str
Push(OPND, str); // 将字符串str压入OPTR栈
scanf("%s", str); // 读入下一个字符串str
}
else
{ // 如果字符串str是运算符,使用 Precede() 函数获取OPTR栈顶元素的运算符和字符串str的运算符的优先级
switch (Precede(GetTop(OPTR), str)) // 使用 Precede() 函数获取相应优先级
{
case '<':
Push(OPTR, str); // 将字符串str压入OPTR栈
scanf("%s", str); // 读入下一个字符串str
break;
case '>':
strcpy(theta, Pop(OPTR)); // 弹出OPTR栈顶的运算符字符串并赋值给变量 theta
strcpy(b, Pop(OPND)); // 弹出OPND栈顶的数值字符串并赋值给变量 b
strcpy(a, Pop(OPND)); // 弹出OPND栈顶的数值字符串并赋值给变量 a
char temp_str[MAXSIZE];
strcpy(temp_str, float_to_str(Operate(a, theta, b))); // 根据相应的三个字符串进行运算,把结果赋给temp_str
Push(OPND, temp_str); // 将运算结果 temp_str 压入OPND栈
break;
case '=':
Pop(OPTR); // 弹出OPTR栈顶的运算符字符串
scanf("%s", str); // 读入下一个字符串str
break;
default:
printf("错误!!!\n该优先级不存在!!!");
}
}
}
printf("%s\n", GetTop(OPND));
} int main(void)
{
EvaluateExpression(); system("pause");
return ;
}

运行结果:

C语言之四则运算表达式求值(链栈)—支持浮点型数据,负数, 整型数据运算的更多相关文章

  1. 数据结构课程设计四则运算表达式求值(C语言版)

    本系统为四则运算表达式求值系统,用于带小括号的一定范围内正负数的四则运算标准(中缀)表达式的求值.注意事项:    1.请保证输入的四则表达式的合法性.输入的中缀表达式中只能含有英文符号"+ ...

  2. C/C++ 语言中的表达式求值

    在此,首先向裘老师致敬! 裘宗燕:C/C++ 语言中的表达式求值 经常可以在一些讨论组里看到下面的提问:“谁知道下面C语句给n赋什么值?” m = 1; n = m+++m++; 最近有位不相识的朋友 ...

  3. C/C++ 语言中的表达式求值(原文作者:裘宗燕)

    经常可以在一些讨论组里看到下面的提问:“谁知道下面C语句给n赋什么值?”m = 1; n = m+++m++;最近有位不相识的朋友发email给我,问为什么在某个C++系统里,下面表达式打印出两个4, ...

  4. 表达式求值(栈方法/C++语言描述)(二)

    上篇中完成了对表达式求值的整体过程,接下来看看如何处理不同类型的token. 对运算数的处理比较简单,它直接调用函数strtod(),将字符串中的运算数转换为浮点类型并将它压入运算数栈中: void ...

  5. 【NYOJ-35】表达式求值——简单栈练习

    表达式求值 时间限制:3000 ms  |  内存限制:65535 KB 难度:3   描述 Dr.Kong设计的机器人卡多掌握了加减法运算以后,最近又学会了一些简单的函数求值,比如,它知道函数min ...

  6. Matrix Chain Multiplication(表达式求值用栈操作)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1082 Matrix Chain Multiplication Time Limit: 2000/100 ...

  7. 河南省acm第九届省赛--《表达式求值》--栈和后缀表达式的变形--手速题

    表达式求值 时间限制:1000 ms | 内存限制:65535 KB 难度:3   描述 假设表达式定义为:1. 一个十进制的正整数 X 是一个表达式.2. 如果 X 和 Y 是 表达式,则 X+Y, ...

  8. 表达式求值(栈方法/C++语言描述)(一)

    一个算数表达式(以下简称为表达式)由运算数.运算符.左括号和右括号组成,定义一个枚举类型TokenType表示为: typedef enum { BEGIN, NUMBER, OPERATOR, LE ...

  9. x86汇编反编译到c语言之——(1)表达式求值及赋值语句

    一. 反编译一种可能的实现方式 我们的目的是将多种平台的汇编如x86,ARM,6502反编译为c语言,所以实现时先将多种汇编转化为 特定虚拟机汇编语言,然后只需要将虚拟机汇编语言反编译为c语言.其中多 ...

随机推荐

  1. Java 之 Properties 集合

    一.Properties 概述 Properties 是Hashtable的子类,不允许key和value是null,并且它的key和value的类型都是String. 二.常用方法 1.构造方法 P ...

  2. javaEE复习重点个人总结

    最近在学院或集队的群里看见最多的就是求javaEE大作业了,那么突然有感而发,写点参考性的期末复习总结. 第一章JavaEE 概述: 1:两层体系应用体系结构 安全性低,部署困难,消耗系统资源 2 三 ...

  3. 使用Python3导出MySQL查询数据

    整理个Python3导出MySQL查询数据d的脚本. Python依赖包: pymysql xlwt Python脚本: #!/usr/bin/env python # -*- coding: utf ...

  4. 阿里云查看本服务器 公网ip地址 命令

    阿里云的服务器用命令ifconfig查看的是本机内网地址 那如何访问公网地址呢? curl httpbin.org/ip

  5. 开放API接口安全处理!

    目录 概念 加密 MD5 Token 开放api参数 重复提交,恶意调用 日志 验证码 开放API接口安全处理! 参考文献: 公钥,私钥和数字签名这样最好理解 (转载) 概念 存在问题: 数据窃取 数 ...

  6. 嵌入式linux开发uboot启动内核的机制(二)

    一.嵌入式系统的分区 嵌入式系统部署在Flash设备上时,对于不同SoC和Flash设备,bootloader.kernel.rootfs的分区是不同的.三星S5PV210规定启动设备的分区方案如下: ...

  7. 从websocket协议出发,了解应用层协议,传输层协议,网络的7层协议

    其他关联连接 :TCP的三次握手(建立连接)和四次挥手(关闭连接) 1.websocket是全双工,不同于传统半双工通信 传统的Web应用中,浏览器与服务器交互都是半双工通信(但并不完全是半双工通信, ...

  8. NOIP 2013 积木大赛

    洛谷 P1969 积木大赛 洛谷传送门 JDOJ 2229: [NOIP2013]积木大赛 D2 T1 JDOJ传送门 题目描述 春春幼儿园举办了一年一度的"积木大赛".今年比赛的 ...

  9. SpringMVC的乱码问题

    1:表单提交controller获得中文参数后乱码解决方案 注意: jsp页面编码设置为UTF-8 form表单提交方式为必须为post,get方式下面spring编码过滤器不起效果 <%@ p ...

  10. 为什么说JAVA程序员必须掌握SpringBoot?

    原文链接:https://w.url.cn/s/AuDahfb SpringBoot 2.0 的推出又激起了一阵学习 SpringBoot 热,那么, SpringBoot 诞生的背景是什么?Spri ...