标识符树与表达式求值

合集下载

c语言运算符和表达式

c语言运算符和表达式

C语言运算符和表达式C语言把除了控制语句和输入输出以外几乎所有的基本操作都作为运算符处理。

1自增(++)、自减(-一)运算符:自增(++)、自减(一)运算符的作用是使变量的值加1或减1,例如,++ii(在使用之前,先使的值加(减)1)i++,i-(在使用i之后,使i的值加(减)1)y++i和i++的不同之处在于:++i是先执行i=i+1,再使用i的值;而i++是先使用i的值,再执行i=i+lβ自增(减)运算符常用于循环语句中,使循环变量自动加1;也用于指针变量,使指针指向下一个地址。

2算术表达式和运算符的优先级与结合性用算术运算符和括号将运算对象连接起来的、符合C语法规则的式子称C 算术表达式。

运算对象包括常量、变量、函数等。

c语言规定了运算符的优先级(如先乘除后加减),还规定了运算符的结合性。

在表达式求值时,先按运算符的优先级别顺序执行,如果在一个运算对象两侧的运算符的优先级别相同,C语言规定了各种运算符的结合方向(结合性),算术运算符的结合方向都是〃自左至右〃,即运算对象先与左面的运算符结合。

算术运算符是自左至右(左结合性),赋值运算符是自右至左(右结合性)。

赋值运算符和赋值表达式赋值运算符就是二,表示〃存储〃,即把赋值号右边表达式的值存给左边的变量。

可以出现在赋值号左边的式子,称为左值(Ieftvalue)o左值必须有内存空间且允许赋值。

常用的左值是变量,但常变量不能作为左值。

赋值运算符的结合性,从右至左。

若有两个赋值号,要先执行右边的。

如:a=b=2相当于是a=(b=2).3不同类型数据间的混合运算在程序中经常会遇到不同类型的数据进行运算,如果一个运算符两侧的看据类型不同,则先自动进行类型转换,使二者成为同一种类型,然后进行运算。

整型、实型,字符型数据间可以进行混合运算。

规律为1)十、-\/运算的两个数中有一个数为float或double型,结果是double 型,因为系统将所有float型数据都先转换为double型,然后进行运算。

c语言算术表达式求值

c语言算术表达式求值

c语言算术表达式求值【实用版】目录1.引言2.C 语言算术表达式的基本概念3.C 语言算术表达式的求值方法4.实际应用示例5.总结正文【引言】在 C 语言编程中,算术表达式是用来进行数值计算的重要工具。

本篇文章将为大家介绍 C 语言算术表达式的求值方法。

【C 语言算术表达式的基本概念】C 语言中的算术表达式主要包括以下几种:1.一元运算符:例如+、-、*、/等,用于对一个数值进行操作。

2.二元运算符:例如+、-、*、/等,用于对两个数值进行操作。

3.关系运算符:例如<、>、<=、>=、==、!=等,用于比较两个数值的大小或相等性。

4.逻辑运算符:例如&&、||、! 等,用于进行逻辑判断。

【C 语言算术表达式的求值方法】C 语言中,算术表达式的求值主要遵循以下规则:1.先进行括号内的运算,再进行括号外的运算。

2.先进行乘除法运算,再进行加减法运算。

3.关系运算符和逻辑运算符的优先级较低,从左到右依次进行运算。

【实际应用示例】下面我们通过一个实际的 C 语言程序,来演示算术表达式的求值过程。

```c#include <stdio.h>int main() {int a = 10, b = 5;int result;result = a + b * (a - b) / (a * b);printf("The result is: %d", result);return 0;}```在这个程序中,我们定义了两个整数变量 a 和 b,并通过算术表达式计算 result 的值。

根据我们之前提到的算术表达式求值规则,我们可以将这个表达式分解为以下几个步骤:1.计算括号内的值:a - b = 10 - 5 = 52.计算乘法运算:b * (a - b) = 5 * 5 = 253.计算除法运算:(a * b) / (a * b) = 14.计算加法运算:a + 25 = 10 + 25 = 355.输出结果:printf("The result is: %d", result); 输出 35【总结】通过本篇文章的介绍,相信大家已经对 C 语言算术表达式的求值方法有了更加深入的了解。

配价语法分析范文

配价语法分析范文

配价语法分析范文一、什么是配价语法分析?配价语法分析是一种用于计算机编程语言的语法分析方法,主要用于确定语法结构中各个组成元素之间的相对优先级和结合性。

在编程语言中,不同的操作符和操作数必须按照一定的规则组合,才能正确表达程序逻辑。

配价语法分析的目的就是按照这些规则对程序进行分析和解释,以确定其结构和功能。

二、为什么需要配价语法分析?编程语言中经常使用了大量的操作符,比如加减乘除、逻辑运算符、赋值运算符等等。

这些操作符之间的优先级和结合性是编程语言的基本规则之一,它决定了哪些操作要先执行,哪些操作要后执行。

如果不进行配价语法分析,编译器或解释器将无法正确解析程序的含义,导致程序逻辑错误。

三、配价语法分析的基本原理1.文法定义配价语法分析通过文法来定义程序语法结构以及操作符的优先级和结合性。

文法可以使用EBNF(扩展巴科斯范式)或BNF(巴科斯-诺尔范式)表示。

一般来说,一个文法包含终结符和非终结符两类符号,终结符对应具体的编程语言中的关键字、标识符、操作符等,而非终结符则表示语法规则中的语法结构。

2.符号优先级和结合性3.算符关系表和算符堆栈4.操作符的转化和计算在进行配价语法分析过程中,需要将操作符转化为对应的功能代码或指令,以实现具体的计算。

转化过程根据操作符的优先级和结合性确定操作执行的顺序,并生成相应的计算代码。

四、典型的配价语法分析方法1.算符优先法算符优先法是一种常用的配价语法分析方法,通过维护一个算符堆栈和一个操作数堆栈来进行分析。

算符优先法使用算符关系表和文法规则来确定操作符之间的优先级和结合性,从而决定操作执行的顺序。

2.LR法LR法是一种基于自底向上的配价语法分析方法,使用状态机和移进-规约动作表来进行解析。

LR法通过分析输入串和产生式来进行规约和移进操作,直到得到完整的语法解析树。

3.LL法LL法是一种基于自顶向下的配价语法分析方法,通过向前看一个输入符号来进行预测和匹配。

字符串表达式求值(支持多种类型运算符)

字符串表达式求值(支持多种类型运算符)

字符串表达式求值(⽀持多种类型运算符)⼀、说明1. 输⼊字符串为中缀表达式,⽆需转为后缀表达式2. ⽀持的运算符包括:算术运算符:"+,-,*,/"关系运算符:">,<,>=,<=,=,!="(注意等于运算符采⽤的是⼀个等号)逻辑运算符:"&&,||"3. ⽀持⼤于10的数字,不⽀持负数操作数,但⽀持中间结果和返回值为负数⼆、算法原理&步骤本⽂算法对中缀表达式形式字符串进⾏求值,同时⽀持与或运算和逻辑运算(若含有关系运算符或者逻辑运算符,则输出为1或者0)。

类似于加减乘除,将关系运算符和逻辑运算符看作优先级低的运算符进⾏处理,优先级:算术运算符>关系运算符>逻辑运算符。

步骤:1. 初始化两个空堆栈,⼀个存放操作数,⼀个存放运算符。

2. 从左⾄右扫描输⼊字符串,依次读取。

2.1 若为操作数,则压⼊操作数栈;2.2 若为运算符,判断其优先级是否⼤于运算符栈栈顶元素优先级。

若⼤于栈顶元素优先级,则直接压栈;否则,弹出栈顶元素operator,同时依次从操作数栈中弹出两个元素number1,number2,计算表达式(number2 operator number1)的值value,并将值value压⼊操作数栈。

重复上述过程直⾄当前扫描的操作符优先级⼤于栈顶元素,然后将当前运算符压栈。

3. 弹出运算符栈顶元素operator,同时依次从操作数栈中弹出两个元素number1,number2,计算表达式(number2 operator number1)的值value,并将值value压⼊操作数栈。

重复上述过程直⾄运算符栈为空。

4. 此时操作数栈应该只有⼀个元素,即为表达式的值。

三、代码&测试求值函数:1/* 字符串表达式求值2 * @param input: 输⼊的字符串3 * @param output: 表达式的值,若含有关系运算符则为1或者04 * return 计算过程是否正常5*/6bool ExpValue(string input,int& output)7 {8 stack<int> operand_stack;9 stack<string> operator_stack;1011char prev = 0; // 上⼀个属于运算符的字符12for (int i = 0; i < input.size(); i++)13 {14char c = input[i];15// prev是否是⼀个完整运算符16if (!isOperator(c) && prev)17 {18string new_op = string("").append(1, prev);19 addNewOperator(new_op, operand_stack, operator_stack);20 prev = 0;21 }2223// 数字24if (isdigit(c))25 {26int val_c = c - '0';27if (i > 0 && isdigit(input[i - 1]))28 {29int top_num = operand_stack.top();30 top_num = top_num * 10 + val_c;31 operand_stack.pop();32 operand_stack.push(top_num);33 }34else35 operand_stack.push(val_c);36 }37// 运算符字符38else if (isOperator(c))39 {40// 处理两字符运算符41if (prev)42 {43string new_op = string("").append(1, prev).append(1, c);44 addNewOperator(new_op, operand_stack, operator_stack);45 prev = 0;46 }47else48 prev = c;49 }50else if (c == '(')51 operator_stack.push("(");52else if (c == ')')53 {54// 处理括号内的运算符55while (operator_stack.top()!="(")56 {57int num1 = operand_stack.top();58 operand_stack.pop();59int num2 = operand_stack.top();60 operand_stack.pop();61string op = operator_stack.top();62 operator_stack.pop();6364int val = Calculate(num2, num1, op);65 operand_stack.push(val);66 }67 operator_stack.pop(); // 弹出"("68 }69 }70 assert(operand_stack.size() == operator_stack.size() + 1);71// 弹出所有运算符72while(!operator_stack.empty())73 {74int num2 = operand_stack.top();75 operand_stack.pop();76int num1 = operand_stack.top();77 operand_stack.pop();78string op = operator_stack.top();79 operator_stack.pop();8081int val = Calculate(num1, num2, op);82 operand_stack.push(val);83 }8485if (operand_stack.size() == 1) {86 output = operand_stack.top();87return true;88 }89return false;90 }其中⽤到的⼦函数有:/* 判断字符是否属于运算符 */bool isOperator(char c){switch (c){case'-':case'+':case'*':case'/':case'%':case'<':case'>':case'=':case'!':case'&':case'|':return true;default:return false;}}/* 获取运算符优先级 */int getPriority(string op){int temp = 0;if (op == "*" || op == "/" || op == "%")temp = 4;else if (op == "+" || op == "-")temp = 3;else if (op == ">" || op == "<" || op == ">=" || op == "<="|| op == "=" || op == "!=")temp = 2;else if (op == "&&" || op == "||")temp = 1;return temp;}/** 返回⼀个两元中缀表达式的值* syntax: num_front op num_back* @param num_front: 前操作数* @param num_back: 后操作数* @param op: 运算符*/int Calculate(int num_front, int num_back, string op){if (op == "+")return num_front + num_back;else if (op == "-")return num_front - num_back;else if (op == "*")return num_front * num_back;else if (op == "/")return num_front / num_back;else if (op == "%")return num_front % num_back;else if (op == "!=")return num_front != num_back;else if (op == ">=")return num_front >= num_back;else if (op == "<=")return num_front <= num_back;else if (op == "=")return num_front == num_back;else if (op == ">")return num_front > num_back;else if (op == "<")return num_front < num_back;else if (op == "&&")return num_front && num_back;else if (op == "||")return num_front || num_back;return0;}/* 新运算符⼊栈操作 */void addNewOperator(string new_op, stack<int>& operand_stack, stack<string>& operator_stack) {while (!operator_stack.empty() && getPriority(operator_stack.top()) >= getPriority(new_op)){int num2 = operand_stack.top();operand_stack.pop();int num1 = operand_stack.top();operand_stack.pop();string op = operator_stack.top();operator_stack.pop();int val = Calculate(num1, num2, op); operand_stack.push(val);}operator_stack.push(new_op);}View Code测试结果:int main(){string s0 = "10-1*10+3%2";string s1 = "100 + (3-33)*2";string s2 = "20+1 >= 20 && 20+1 < 20"; string s3 = "10>20 || 10/1>=5";int ret = -1;if (ExpValue(s0, ret))cout << s0 << "的值: " << ret << endl; if (ExpValue(s1, ret))cout << s1 << "的值: " << ret << endl; if (ExpValue(s2, ret))cout << s2 << "的值: " << ret << endl; if (ExpValue(s3, ret))cout << s3 << "的值: " << ret << endl; return0;}上述代码的执⾏结果为:。

C#算术表达式求值(后缀法),看这一篇就够了

C#算术表达式求值(后缀法),看这一篇就够了

C#算术表达式求值(后缀法),看这⼀篇就够了⼀、种类介绍算术表达式有三种:前缀表达式、中缀表达式和后缀表达式。

⼀般⽤的是中缀,⽐如1+1,前后缀就是把操作符移到前⾯和后⾯,下⾯简单介绍⼀下这三种表达式。

1、前缀表⽰法前缀表⽰法⼜叫波兰表⽰法,他的操作符置于操作数的前⾯(例:+ 1 2),是波兰数学家扬·武卡谢维奇1920年代引⼊的,⽤于简化命题逻辑。

因为我们⼀般认为操作符是在操作数中间的,所以在⽇常⽣活中⽤的不多,但在计算机科学领域占有⼀席之地。

⼀般的表⽰法对计算机来说处理很⿇烦,每个符号都要考虑优先级,还有括号这种会打乱优先级的存在,将使计算机花费⼤量的资源进⾏解析。

⽽前缀表⽰法没有优先级的概念,他是按顺序处理的。

举个例⼦:9-2*3这个式⼦,计算机需要先分析优先级,先乘后减,找到2*3,再进⾏减操作;化成前缀表⽰法就是:- 9 * 2 3,计算机可以依次读取,操作符作⽤于后⼀个操作数,遇到减就是让9减去后⾯的数,⽽跟着9的是乘,也就是说让9减去乘的结果,这对计算机来说很简单,按顺序来就⾏了。

2、中缀表⽰法这也就是我们⼀般的表⽰法,他的操作符置于操作数的中间(例:1 + 2),前⾯也说过这种⽅法不容易被计算机解析,但他符合⼈们的普遍⽤法,许多编程语⾔也就⽤这种⽅法了。

在中缀表⽰法中括号是必须有的,要不然运算顺序会乱掉。

3、后缀表⽰法后缀表⽰法⼜叫逆波兰表⽰法,他的操作符置于操作数的后⾯(例:1 2 +),他和前缀表⽰法都对计算机⽐较友好,但他很容易⽤堆栈解析,所以在计算机中⽤的很多。

他的解释过程⼀般是:操作数⼊栈;遇到操作符时,操作数出栈,求值,将结果⼊栈;当⼀遍后,栈顶就是表达式的值。

因此逆波兰表达式的求值使⽤堆栈结构很容易实现,且能很快求值。

注意:逆波兰记法并不是简单的波兰表达式的反转。

因为对于不满⾜交换律的操作符,它的操作数写法仍然是常规顺序,如,波兰记法/ 6 3的逆波兰记法是6 3 /⽽不是3 6 /;数字的数位写法也是常规顺序。

根据数据元素之间的逻辑关系,一般有哪几类基本的数据结构?并说明数据元素之间存在的关系。

根据数据元素之间的逻辑关系,一般有哪几类基本的数据结构?并说明数据元素之间存在的关系。

根据数据元素之间的逻辑关系,一般有哪几类基本的数据结构?并说明数据元素之间存在的关系。

数据结构与逻辑关系1. 引言数据结构是计算机科学中非常重要的一个概念,它描述了数据元素之间的逻辑关系。

在实际应用中,根据数据元素之间的逻辑关系,我们可以将数据结构分为多个基本类型。

本文将介绍常见的几类基本的数据结构,并详细说明数据元素之间存在的关系。

2. 数组数组是最简单、最常见的数据结构之一。

它由相同数据类型的元素组成,这些元素按照一定的顺序存放在连续的内存空间中。

数组元素之间的关系可以用下标表示,即通过索引可以直接访问数组中的元素。

这使得数组具有随机访问的优势。

数组的一个重要特点是固定长度,一旦创建之后,大小不能再改变。

这意味着在插入和删除元素时,需要移动其他元素的位置。

因此,数组适用于对元素的访问频繁,但插入和删除操作较少的场景。

链表是数据结构中另一种常见的形式。

链表中的元素由节点组成,每个节点除了包含数据外,还保存了指向下一个节点的指针。

节点之间的关系通过指针建立起来。

链表具有动态性,可以在运行时添加和删除节点。

相比数组,链表插入和删除的开销较小,不需要移动其他节点。

然而,链表的随机访问较为困难,需要从头节点遍历到目标位置。

链表有多种类型,包括单链表、双链表和循环链表等。

这些不同类型的链表在节点之间的连接方式上存在差异,但它们都是通过指针来建立节点之间的关系。

4. 栈与队列栈和队列是两种受限的数据结构,它们限制了元素的访问和操作方式。

栈是一种后进先出(Last In First Out,LIFO)的数据结构,只允许在栈顶进行插入和删除操作。

栈的元素访问顺序与插入顺序相反。

它可以用来解决一些与时间有关的问题,例如函数调用栈和表达式求值。

队列是一种先进先出(First In First Out,FIFO)的数据结构,插入操作在队尾进行,删除操作在队头进行。

队列可以用来模拟一些实际生活中的场景,如排队和任务调度。

逆波兰式探微——后缀表达式的求法及其适用情况比较

逆波兰式探微——后缀表达式的求法及其适用情况比较
维普资讯

科 苑论 谈 ljl
逆波 兰 式探微
后缀 表达式 的求法及其 适用情况 比较
郭 群

( 宁对外经贸学院 , 宁 大连 16 5 ) 辽 辽 10 2
摘 要: 介绍数据结构学科 中的一个重要领 域——后缀表达式 ( 波兰式 ) 逆 的求法。通过栈 的应用、 标识符树 、 号转换三种方 法讨论后缀表达 扩
式 实现 方 法 以及 它 们 的 适 用 范 围 。
关键词 : 后缀表 达式 ; ; 栈 标识符树 ; 号转换 扩
1概 述 符号栈 。
1 中缀表达式( o t n。 . 1 I N t i ) —般我们所 x ao 2 A遇到结束符“ ’ . 1 , 运算符 号栈 内的 则把 用表达式是将运算符号放在两个运算对象的 中 所有运算符号依次弹 出, 并压 ^ 出符号栈 。 输 间 , : bc 等等, 比如 a , d + / 我们把这样的式子称为 中 2 . 输人为 “” . 若 1 5 一 的单 目 运算符 , 改为 0 与 缀表达式。中 缀表达式在运算时既要考 虑括号的 运算对象在前, 运算符在后。 ’ 作用, 要考虑运算符的优先级 , 还要考虑运算符出 例如:3+4/ 5一6+1 ) 8# ( 2 ( 5) 前缀表达式 : A B * DE + G , — C + 一F H + 现的先后次序。因此各运算符实际的运算次序往 2 2后缀表达式求值 后§ 达式 : C + E F + 疆 AB 一 D + G H一 / 往同它们在表达式中出现的先后 次序是不一致 2 .后缀表达式求值用 到一个数栈和一个 2 1 4括号转换 的, 是不可预测的。 存放后缀表达式的字符型数组。其实现过程就是 求后缀表达式 的问题不但在计算机编译程 1 2前缀表达式(D o t n 。前缀表达 从头至尾扫描数组中的后缀表达式: P xN t i ) ao 序中十分有用 , 而且是数据结构学科、 各类计算机 式, 也称为波兰表达式 , 是为了纪念波兰数学家鲁 2 . 当遇到运算对象时就把它压人到数栈 升学考试,以及全国计算机等级考试和高级程序 . 21 1 卡谢维奇( nL ks wc) J u ai i 而命名的。 a e z 在前缀表达 中; 员考试中常考 的题型, 在理论考试中都需要 比 较 式中, 运算符出 现在两个运算对象( 操作数) 之前。 2. , 2当遇到运算符时,就执行两次出 的 多的时间。 2 1 栈  ̄: t C—A }B+D 的前经 为 : l l 舀 式 +一C 操作, 对出栈的数进行该运算符指定的运算 , 并把 下面介绍一种使用 园扩号转换求后缀表达 A 。 B D 计 的 算 结果压人 膨盹 。 蛰 式的方法 , 在理论考试中可以方便地将中缀表达 1 3后缀表达式(otxN tt n。后缀表达 P si o i ) f ao 2 2 3重复 2 . 、.1 , 1 .1 2 . 直至扫描到表 达式 式转换为后缀表达式。 2. 2. 1 2 式规定把运算符放在两个运算对象的后面。在后 的终止符‘” 辞, 在数栈的栈顶得到表达式的值。 41 .转换步骤 缀表达式 中, 不存在运算符的优先级 问题, 也不存 【 】 例 后缀表达式 3 56 1 42 5+一/ 8} 4 ,将 中缀表达式根据运算先后次序全部 1 1 在任何括号 , 计算 的顺序完全按照运算符 出现的 + ̄ - t - g过程 : ' 用圆扩号扩起来; 先后次序进行。 比中缀表达式的求值要简单得多。 3 56 5十一/8}+ 42 1 61 + 5的结果为:1 2 4 .移动所有运算符 号来取代所有的右括 J 2 比如中缀表达式 :— * + , C A B D 其后缀表达式 号, 以最近为原则进行替换; 并 为 : C A B}一D +。 2— 1 5 2 的结果为 : 4 4 .删除所有的左括弧 ,即得到后缀表达 . 1 3 由于前缀表达式称为波兰表达式 , 所以后缀 式。 表达式也称为逆波兰式。 44的结果为 : / 1 【 将( 例】 A—B+C—D E转换为后缀表 ) 通常编译器在处理运算 时先要将中缀表达 达式 为 A B—C+D E } 一 式转换为后缀表达式然后再进行运算。 1 8的结果为 : " 8 使用括 号转换法 的转换过程和方法十分简 2栈 的应 用 单。 掌握这种方法, 对付理论考试中关于求后缀表 21 .转换方法。转换过程需要两个栈 : —个运 3 8的结果为:1 达式的棚念 陛的试题是十分有效的, + 1 且不易出 错。 算符号栈和—个后缀表达式输出符号栈。 3标识符树 如果用园括号转换法编写程序 , 则其效率却 2. 人 1 读 操作数 , 1 直接送输出符号栈。 将算术表达式用二叉树来表示 , 称为标识符 是非常低。 因是计算机在处理中 原 缀表达式时. 必 2 .读 人 . 1 2 运算符 , 入 压 运算 号 。 }栈 树, 也称为二叉表示树 。 须对表达式字符串进行两次扫描: z 21 1 若后进的运算符优先级高于先进的 , 3 标识符树的特点 : . 1 第一次扫描先读取整个表达式 , 并依据步骤 则继续进栈; 3 .运算对象 ( .1 1 标识符) 都是叶结点。 41 插入括号 ; .1 . 2 . 若 后进 的运算符优先级不高于先进 .. 12 2 3 .运算符都是根结点 。 . 1 2 第二次扫描是为 了移动运算符 以取代一个 的, 则将运算符号栈内高于或等于后进运算符级 3 .对算术表达式 的标识符树进行后序遍 适当的右括号, . 1 3 如步骤 4 . .2 1 别的 运算符依次弹出后, 自己进栈。 历, 能方便地得至原算术表达式的后缀表达式。 J 『 最后再删 除全部左括号 , 如步骤 4 . 才 能 . , 1 3 21 .3括号处理 : . 3 从表达式产生标识符树的方法: . 2 完或整个转换过程。 2 .1 . .遇到开括号“”进运算符号栈 ; 1 3 (, 3. .1 2 读人表达式的一部分产 生相应 二叉树 5结 论 2 1 2 后 , .. 3 再读人运算符时, 与二叉树根结点的运算符 比 5 若单纯 的求后缀表达式 , 以第一种方 . 1 则 遇 到闭 括 较优先级的高低: 2 .读人优先级高于根结点的 法 , 3 .1 .1 即利用堆栈求后缀表达式的方法为好。 号 “”则 优先级 , ), 则读人的运算符作为根的右子树 , 原来二 5 2若同时求表达式的前缀表达式和后缀表 把最 靠 近 叉树的右子 ,成为读人运算符的左子树;2 2 达式的话, 以 树 3, 1 则 利用标识符树的方法为好。 它的特 的开 括号 读人优先级不高 ( 等于或低于根结点的优先级 ) 点是求得表达式 的标识符树 以后,其前序遍历的 。 “” ( 。以及 则读人运算符作为树根,而原来二叉树作为它的 序列 即前缀表达式 ; 而后序遍历 的 序列即后缀表 h 1 L 4 6 6 .2* + 黻 其 后进 栈 左子树 ; 达式。 I ^ L1 2 #出 的运算 符 3 .遇到括号先使括号 内的表达式产生一 . 2 2 5 若只是为 了 _ 3 解答考题中出现的求后缀表 L l 1 L 一 2 1 量) , : 2十 《 ■出 依 次弹 出 棵二叉树 , 再把它的根结点连到前面已产生的二 达式的结果 , 符日 而不考虑如何用程序去实现的话 , 则 l , 1 1 一 遇) 冼弹 * 1十 《 , 到输 出符 叉 树根结点的右子树 E 去。 符日 使用圆括号转换法求后缀表达式的方法无疑是最 } 地 41 1 / ■出 ^ 目 十^ 螂 ≈琏 埔 挠 8 ^ 2* 1 6 1 h B 号栈 , 但 3 应用举例 . 3 佳的。 ● 2i^ 1 ^ 1 l * , ■ 括号 均不 【 】 出(+B c )( + (+ — )的 例 画 A (— ) ( E FG H ) /D 参 考文 献 压 人 输 出 标识符树 , 并求它的前序序列和后序序列。 [ 1 ]陈元春 , 张亮 , 勇. 王 实用 ( 下转 2 2页 ) 6

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

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

数据结构课程设计四则运算表达式求值(C语⾔版) 明⼈不说暗话,直接上,输⼊提取码z3fy即可下载。

⽂件中包含程序,程序运⾏⽂件,设计报告和测试样例,应有尽有,欢迎⼩伙伴们在中下载使⽤。

本课程设计为四则运算表达式求值,⽤于带⼩括号的⼀定范围内正负数的四则运算标准(中缀)表达式的求值。

注意事项:1、请保证输⼊的四则表达式的合法性。

输⼊的中缀表达式中只能含有英⽂符号“+”、“-”、“*”、“/”、“(”、“)”、“=”、数字“0”到“9”以及⼩数点“.”,输⼊“=”表⽰输⼊结束。

例如9+(3-1)*3.567+10/2=,特别是请勿输⼊多余空格和中⽂左右括号。

2、输⼊的中缀表达式默认限定长度是1001,可根据具体情况调整字符串数组的长度。

3、请保证输⼊的操作数在double数据类型范围内,单个数字有效数字长度不可超过15位。

本课程设计中操作数是C语⾔中的双精度浮点数类型。

4、本课程设计中的运算数可以是负数,另外如果是正数可直接省略“+”号(也可带“+”号)。

 下⾯的程序正常运⾏需要在上⾯的百度⽹盘中下载相应⽂件,否则⽆法正常使⽤哦。

1/*本程序为四则运算表达式求值系统,⽤于计算带⼩括号的四则运算表达式求值。

2具体算法:3先将字符串处理成操作单元(操作数或操作符),再利⽤栈根据四则运算4的运算法则进⾏计算,最后得出结果。

*/56 #include<stdio.h>7 #include<ctype.h>8 #include<stdlib.h>9 #include<string.h>10 #include<stdlib.h>11 #include<ctype.h>1213const int Expmax_length = 1001;//表达式最⼤长度,可根据适当情况调整14struct Ope_unit15 {//定义操作单元16int flag;//=1表⽰是操作数 =0表⽰是操作符 -1表⽰符号单元17char oper;//操作符18double real;//操作数,为双精度浮点数19 };2021void Display();//菜单22void Instru(); //使⽤说明23int Check(char Exp_arry[]);24void Evalua(); //先调⽤Conver操作单元化,再调⽤Calculate函数计算结果并输出25int Conver(struct Ope_unit Opeunit_arry[],char Exp_arry[]);//将字符串处理成操作单元26int Isoper(char ch);//判断合法字符(+ - * / ( ) =)27int Ope_Compar(char ope1,char ope2);//操作符运算优先级⽐较28double Calculate(struct Ope_unit Opeunit_arry[],int Opeunit_count,int &flag);//⽤栈计算表达式结果29double Four_arithm(double x,double y,char oper);//四则运算3031int main()32 {33int select;34while(1)35 {36 Display();37 printf("请输⼊欲执⾏功能对应的数字:");38 scanf("%d",&select);39 printf("\n");40switch(select)41 {42case1: Evalua(); break;43case2: Instru(); break;44case0: return0;45default : printf("⽆该数字对应的功能,请重新输⼊\n");46 system("pause");47 }48 }49return0;50 }5152int Check(char Exp_arry[])53 {//检查是否有⾮法字符,返回1表⽰不合法,0表⽰合法54int Explength=strlen(Exp_arry),i;55for(i=0;i<Explength;i++)56 {57if(!Isoper(Exp_arry[i]) && Exp_arry[i] != '.' && !isdigit(Exp_arry[i]))58return1;59if(isdigit(Exp_arry[i]))60 {61int Dig_number=0,Cur_positoin=i+1;62while(isdigit(Exp_arry[Cur_positoin]) || Exp_arry[Cur_positoin]=='.')63 {64 Dig_number++;65 Cur_positoin++;66 }67if(Dig_number >= 16)//最多能够计算15位有效数字68return1;69 }70 }71return0;72 }7374void Evalua()75 {//先调⽤Conver函数将字符串操作单元化,再调⽤Calculate函数计算结果并输出76char Exp_arry[Expmax_length];77int flag=0;//假设刚开始不合法,1表达式合法,0不合法78struct Ope_unit Opeunit_arry[Expmax_length];7980 getchar();//吃掉⼀个换⾏符81 printf("请输⼊四则运算表达式,以=结尾:\n");82 gets(Exp_arry);83 flag=Check(Exp_arry);84if(flag)85 printf("该表达式不合法!\n");86else87 {88int Opeunit_count = Conver(Opeunit_arry,Exp_arry);89double ans = Calculate(Opeunit_arry,Opeunit_count,flag);90if(flag)91 {92 printf("计算结果为:\n");93 printf("%s%lf\n",Exp_arry,ans);94 }95else96 printf("该表达式不合法!\n");97 }98 system("pause");99 }100101int Conver(struct Ope_unit Opeunit_arry[],char Exp_arry[])102 {//将字符串操作单元化103int Explength=strlen(Exp_arry);104int i,Opeunit_count=0;105for(i=0;i<Explength;i++)106 {107if(Isoper(Exp_arry[i]))//是操作符108 {109 Opeunit_arry[Opeunit_count].flag=0;110 Opeunit_arry[Opeunit_count++].oper=Exp_arry[i];111 }112else//是操作数113 {114 Opeunit_arry[Opeunit_count].flag=1;115char temp[Expmax_length];116int k=0;117for(; isdigit(Exp_arry[i]) || Exp_arry[i]=='.' ;i++)118 {119 temp[k++]=Exp_arry[i];120 }121 i--;122 temp[k]='\0';123 Opeunit_arry[Opeunit_count].real=atof(temp);//将字符转化为浮点数124125//负数126if(Opeunit_count == 1 && Opeunit_arry[Opeunit_count-1].flag==0127 && Opeunit_arry[Opeunit_count-1].oper=='-')128 {129 Opeunit_arry[Opeunit_count-1].flag = -1;130 Opeunit_arry[Opeunit_count].real *= -1;131 }// -9132if(Opeunit_count >= 2 && Opeunit_arry[Opeunit_count-1].flag==0133 && Opeunit_arry[Opeunit_count-1].oper=='-' && Opeunit_arry[Opeunit_count-2].flag==0 134 && Opeunit_arry[Opeunit_count-2].oper !=')')135 {136 Opeunit_arry[Opeunit_count-1].flag = -1;137 Opeunit_arry[Opeunit_count].real *= -1;138 }// )-9139140//正数141if(Opeunit_count == 1 && Opeunit_arry[Opeunit_count-1].flag==0142 && Opeunit_arry[Opeunit_count-1].oper=='+')143 {144 Opeunit_arry[Opeunit_count-1].flag = -1;145 }// +9146if(Opeunit_count >= 2 && Opeunit_arry[Opeunit_count-1].flag==0147 && Opeunit_arry[Opeunit_count-1].oper=='+' && Opeunit_arry[Opeunit_count-2].flag==0148 && Opeunit_arry[Opeunit_count-2].oper !=')')149 {150 Opeunit_arry[Opeunit_count-1].flag = -1;151 }// )+9152 Opeunit_count++;153 }154 }155/*for(i=0;i<Opeunit_count;i++)156 {//查看各操作单元是否正确,1是操作数,0是操作符157 if(Opeunit_arry[i].flag == 1)158 printf("该单元是操作数为:%lf\n",Opeunit_arry[i].real);159 else if(Opeunit_arry[i].flag == 0)160 printf("该单元是操作符为:%c\n",Opeunit_arry[i].oper);161 else162 printf("该单元是负号符为:%c\n",Opeunit_arry[i].oper);163 }*/164return Opeunit_count;165 }166167double Calculate(struct Ope_unit Opeunit_arry[],int Opeunit_count,int &flag)168 {//根据运算规则,利⽤栈进⾏计算169int i,dS_pointer=0,oS_pointer=0;//dS_pointer为操作数栈顶指⽰器,oS_pointer为操作符栈顶指⽰器170double Dig_stack[Expmax_length];//操作数栈(顺序存储结构)171char Ope_stack[Expmax_length];//操作符栈172173for(i=0;i<Opeunit_count-1;i++)174 {175if( Opeunit_arry[i].flag != -1 )176 {177if(Opeunit_arry[i].flag)//是操作数178 {179 Dig_stack[dS_pointer++]=Opeunit_arry[i].real;//⼊操作数栈180//printf("%lf\n",Digit[dS_pointer-1]);181 }182else//是操作符 + - * / ( )183 {184//操作符栈为空或者左括号⼊栈185if(oS_pointer==0 || Opeunit_arry[i].oper=='(')186 {187 Ope_stack[oS_pointer++]=Opeunit_arry[i].oper;188//printf("%oS_pointer\Ope_u_count",Operator[oS_pointer-1]);189 }190else191 {192if(Opeunit_arry[i].oper==')')//是右括号将运算符⼀直出栈,直到遇见左括号193 {194 oS_pointer--;//指向栈顶195 dS_pointer--;//指向栈顶196while(Ope_stack[oS_pointer] != '(' && oS_pointer != 0)197 {198 Dig_stack[dS_pointer-1] = Four_arithm(Dig_stack[dS_pointer-1],Dig_stack[dS_pointer], 199 Ope_stack[oS_pointer--]);//oS_pointer--为操作符出栈200201 dS_pointer--;//前⼀个操作数出栈202//printf("操作数栈顶元素等于%lf\n",Digit[dS_pointer]);203 }204 oS_pointer--;//左括号出栈205206 oS_pointer++;//恢复指向栈顶之上207 dS_pointer++;208 }209else if(Ope_Compar(Opeunit_arry[i].oper,Ope_stack[oS_pointer-1]))//和栈顶元素⽐较210 {211 Ope_stack[oS_pointer++]=Opeunit_arry[i].oper;212//printf("%oS_pointer\Ope_u_count",Operator[oS_pointer-1]);213 }214else//运算符出栈,再将该操作符⼊栈215 {216 oS_pointer--;//指向栈顶217 dS_pointer--;//指向栈顶218while(Ope_Compar(Opeunit_arry[i].oper,Ope_stack[oS_pointer])==0 && oS_pointer != -1) 219 {//当前操作符⽐栈顶操作符优先级⾼220 Dig_stack[dS_pointer-1]=Four_arithm(Dig_stack[dS_pointer-1],Dig_stack[dS_pointer], 221 Ope_stack[oS_pointer--]);222 dS_pointer--;223//printf("操作数栈顶元素等于%lf\n",Digit[dS_pointer]);224 }225 oS_pointer++;//恢复指向栈顶之上226 dS_pointer++;227 Ope_stack[oS_pointer++]=Opeunit_arry[i].oper;228 }229 }230 }231 }232 }233/*for(i=0;i<oS_pointer;i++)234 printf("操作符栈%oS_pointer\Ope_u_count",Operator[i]);235 for(i=0;i<dS_pointer;i++)236 printf("操作数栈%lf\n",Digit[i]);*/237 oS_pointer--;//指向栈顶元素238 dS_pointer--;//指向栈顶元素239while(oS_pointer != -1)240 {241 Dig_stack[dS_pointer-1]=Four_arithm(Dig_stack[dS_pointer-1],Dig_stack[dS_pointer], 242 Ope_stack[oS_pointer--]);//oS_pointer--为操作符出栈243 dS_pointer--;//前⼀个操作数出栈244//printf("操作数栈顶元素为%lf\Ope_u_count",Digit[dS_pointer]);245 }246//printf("%dS_pointer,%dS_pointer\n",oS_pointer,dS_pointer);247if(oS_pointer==-1 && dS_pointer==0)248 flag=1;//为1表⽰表达式合法249return Dig_stack[0];250 }251252int Ope_Compar(char ope1,char ope2)253 {//操作符运算优先级⽐较254char list[]={"(+-*/"};255int map[5][5]={//先⾏后列,⾏⽐列的运算级优先级低为0,⾼为1256// ( + - * /257/* ( */1,0,0,0,0,258/* + */1,0,0,0,0,259/* - */1,0,0,0,0,260/* * */1,1,1,0,0,261/* / */1,1,1,0,0 };262int i,j;263for(i=0;i<5;i++)264if(ope1==list[i]) break;265for(j=0;j<5;j++)266if(ope2==list[j]) break;267return map[i][j];268 }269270double Four_arithm(double x,double y,char oper)271 {//四则运算272switch(oper)//保证不含其它运算符273 {274case'+': return x+y;275case'-': return x-y;276case'*': return x*y;277case'/': return x/y;//y不能为0278default : return0;279 }280 }281282int Isoper(char ch)283 {//判断合法字符 + - * / ( ) =284if(ch=='+' || ch=='-' || ch=='*' || ch=='/' || ch=='(' || ch==')' || ch=='=')285return1;286return0;287 }288289void Display()290 {//打印菜单291 system("cls");292 printf("/******************************************************************************/\n");293 printf("\t\t 欢迎使⽤本四则运算表达式求值系统\n");294 printf("\n\t说明:建议请您先阅读使⽤说明,再输⼊相应的数字进⾏操作,谢谢配合!\n"); 295 printf("\n\t\t1 四则运算表达式求值\n");296 printf("\n\t\t2 使⽤说明\n");297 printf("\n\t\t0 退出\n");298 printf("/******************************************************************************/\n");299 }300301void Instru()302 {//打印使⽤说明303 FILE *fp;304char ch;305if( ( fp=fopen("使⽤说明.txt","r") ) == NULL)306 {307 printf("⽂件打开失败!\n");308 exit(0);309 }310for(; (ch = fgetc(fp)) != EOF; )311 putchar(ch);312 fclose(fp);313 printf("\n");314 system("pause");315 }。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
preorder(ptr->left); // 左子树
preorder(ptr->right); // 右子树
}
}
void inorder(btree ptr) // 表达式二叉树中序输出
{
if (ptr!=NULL) // 终止条件
{
inorder(ptr->left); // 左子树
printf(" %c",ptr->data); // 输出结点内容
电子信息学院
实验报告书
课程名:数据结构
题目:标识符树与表达式求值
实验类别设计
班级:
学号:
姓名:
1、实验内容或题目
(1)定义二叉树的结构如下:
struct tree//定义结构体
{ int data;//定义一个整型数据域
struct tree *left;//定义左子树指针
struct tree *right;//定义右子树指针
if (data[pos]==0||pos>n) // 终止条件
return NULL;
node; // 创建新结点内存
newnode->data=data[pos]; // 创建结点内容
newnode->left=createbtree(data,2*pos); // 创建左子树递归调用
}
}
int getvalue(int op,int operand1,int operand2) // 计算二叉树表达式值
{
switch((char)op)
{
case'*':return(operand1*operand2);
case'/':return(operand1/operand2);
case'+':return(operand1+operand2);
case'-':return(operand1-operand2);
}
}
void main() // 主程序
{
btree root=NULL; // 表达式二叉树指针
int result,k=1; // 定义输出结果变量
int data[100]={' '};
char ch;
printf("按前序输入标识符树的结点数据,以回车键表示结束\n");
inorder(ptr->right); // 右子树
}
}
void postorder(btree ptr) // 表达式二叉树后序输出
{
if(ptr!=NULL) // 右子树
{
postorder(ptr->left); // 左子树
postorder(ptr->right); // 右子树
printf(" %c",ptr->data); // 输出结点内容
}
}
int cal(btree ptr) // 表达式二叉树后序计值
{
int operand1=0; // 定义操作数变量1
int operand2=0; // 定义操作数变量2
int getvalue(int op,int operand1,int operand2); // 对getvalue函数作声明
};
typedef struct tree btnode;//树的结构类型
typedef btnode *bt;//定义树结点的指针类型
(2)把算术表达式2*3+6/3的标识符树(见图7-35)存入一维数组。
(3)求标识符树的前序遍历、中序遍历和后序遍历的序列。
(4)以后序计算标识符树的值。
2、实验目的与要求
if (ptr->left==NULL && ptr->right==NULL) // 终止条件
return ptr->data-48;
{
operand1=cal(ptr->left); // 左子树
operand2=cal(ptr->right); // 右子树
return getvalue(ptr->data,operand1,operand2);
(1)掌握二叉树的数组存储方法。
(2)掌握二叉树的非线性特点、递归特点和动态特性。
(3)复习二叉树遍历算法和标识符树的概念。
(4)利用标识符树的后序计算表达式的值(运算只涉及+、-、*、/)。
3、实验步骤与源程序
实验步骤
1、创建树和指向指针以及表达式二叉树,限定终止条件。
2、创建新结点内存及内容,应用使表达式二叉树分别进行前序输出、中叙输出、后续输出。表达式二叉树后序记值,定义两个操作数变量,并对getvalue函数作声明,建立终止条件。
inorder(root); // 中序输出二叉树
printf("\t\n\n 后序表达式:");
postorder(root); // 后序输出二叉树
result=cal(root); // 计算
printf("\t\n\n 表达式结果是:%d\n\n",result); // 输出计算结果
}
4、测试数据与实验结果(可以抓图粘贴)
while((ch=getchar())!='\n')
data[k++]=ch;
data[k]='\0';
n=k-1;
root=createbtree(data,1); // 创建表达式二叉树
printf("\t\n 前序表达式:");
preorder(root); // 前序输出二叉树
printf("\t\n\n 中序表达式:");
};
typedef struct tree treenode; // 树的结构新类型
typedef treenode *btree; // 声明树结点指针类型
int n; // n计算字符串长度
btree createbtree(int *data,int pos) // 创建表达式二叉树
{
btree newnode; // 新结点指针
3、运行主程序,创建表达式二叉树,定义输出结果变量。
源代码
#include<stdlib.h>
#include<stdio.h>
struct tree // 树的结构声明
{
char data; // 结点数据
struct tree *left; // 指向左子树的指针
struct tree *right; // 指向右子树的指针
newnode->right=createbtree(data,2*pos+1); // 创建右子树递归调用
return newnode;
}
}
void preorder(btree ptr) // 表达式二叉树前序输出
{
if(ptr!=NULL) // 终止条件
{
printf(" %c",ptr->data); // 输出结点内容
相关文档
最新文档