精华内容
下载资源
问答
  • 《数据结构 课程设计表达式求值 实验报告》由会员分享,可在线阅读,更多相关《数据结构 课程设计表达式求值 实验报告(21页珍藏版)》请在人人文库网上搜索。1、实验课程名称 级 专业班 名姓 学生 号学 指导 教 师 20...

    《数据结构 课程设计表达式求值 实验报告》由会员分享,可在线阅读,更多相关《数据结构 课程设计表达式求值 实验报告(21页珍藏版)》请在人人文库网上搜索。

    1、实验课程名称 级 专业班 名姓 学生 号学 指导 教 师 20至 20 学年第学期第至周 0算术表达式求值演示 1、概述 数据结构课程设计,要求学生在数据结构的逻辑特性和物理表示、数据结构的选择和应用、算 法的设计及其实现等方面,加深对课程基本内容的理解。同时,在程序设计方法以及上机操作等基 本技能和科学作风方面受到比较系统和严格的训练。 在这次的课程设计中我选择的题目是算术表达式求值演示。表达式计算是实现程序设计语言的 基本问题之一,也是栈的应用的一个典型例子。设计一个程序,演示用算符优先法对算术表达式求 值的过程。深入了解栈和队列的特性,以便在解决实际问题中灵活运用它们,同时加深对这种结构。

    2、 的理解和认识。 二、 系统分析 1 以字符列的形式从终端输入语法正确的、不含变量的整数表达式。利用已知的算符 优先关系,实现对算术四则混合运算表达式的求值,并仿照教科书的例子在求值中 运算符栈、运算数栈、输入字符和主要操作的变化过程。 2 一般来说,计算机解决一个具体问题时,需要经过几个步骤:首先要从具体问题抽 象出一个适当的数学模型,然后设计一个解决此数学模型的算法,最后编出程序, 进行测试,调试直至得到想要的答案。对于算术表达式这个程序,主要利用栈,把 运算的先后步骤进行分析并实现简单的运算!为实现算符优先算法,可以使用两个 栈,一个用以寄存运算符,另一个用以寄存操作数和运算结果。 3 。

    3、演示程序是以用户于计算机的对话方式执行,这需要一个模块来完成使用者与计算 机语言的转化。 4 程序执行时的命令: 本程序为了使用具体,采用菜单式的方式来完成程序的演示,几乎不用输入什么特 殊的命令,只需按提示输入表达式即可。(要注意输入时格式,否者可能会引起一些错 误) 测试数据。5. 1三、 概要设计 一个算术表达式中除了括号、界限符外,还包括运算数据和运算符。由于运算符有优先级别之 差,所以一个表达式的运算不可能总是从左至右的循序执行。每次操作的数据或运算符都是最近输 入的,这与栈的特性相吻合,故本课程设计借助栈来实现按运算符的优先级完成表达式的求值计算。 算法设计 程序包含三个模块 (1。

    4、) 主程序模块,其中主函数为 void main 输入表达式; 根据要求进行转换并求值; 输出结果; 体求值。表达式求值模块实现具(2) 换。表达式转换模块(3) 实现转 各个函数之间的调用关系 主函数 表达式转换 数据输入表达式求值 输出 输出 2栈的抽象数据类型定义 ADT SqStack 数据对象:D=a| aElemSet,i=1,2,3,n,n0 i i 数据关系:,a | a ,D,i=1,2,3,,n i-1iii-1R1= using namespace std; #define STACK_INIT_SIZE 100 #define STACKINCREMENT 10 typ。

    5、edef struct /运算符栈 char *base; char *top; int stacksize; SqStack1; typedef struct /运算数栈 float *base; float *top; int stacksize; SqStack2; void InitStack1(SqStack1 &S1);/声明栈建立函数 void InitStack2(SqStack2 &S2);/声明栈建立函数 void evaluate(SqStack1 &S1,SqStack2 &S2);/确定如何入栈函数 void Push1(SqStack1 &S1,char e);/声。

    6、明入栈函数 void Push2(SqStack2 &S2,float e);/声明入压栈函数 char GetTop1(SqStack1 &S1);/声明取栈顶元素函数 float GetTop2(SqStack2 &S2);/声明取栈顶元素函数 char Pop1(SqStack1 &S1);/声明出栈函数 float Pop2(SqStack2 &S2);/声明出栈函数 char Compare(char m,char n);/声明比较函数 float Operate(float a,char rheta,float b);/声明运算函数 void DispStack1(SqStack1。

    7、 &S1);/从栈底到栈顶依次输出各元素 void DispStack2(SqStack2 &S2);/从栈底到栈顶依次输出各元素 /*主函数*/ void main() 4SqStack1 S1;/定义运算符栈 SqStack2 S2;/定义运算数栈 /freopen(data1.in,stdin); /freopen(data1.out,w,stdout); InitStack1(S1);/调用栈建立函数 InitStack2(S2);/调用栈建立函数 evaluate(S1,S2);/调用确定如何入栈函数 潣瑵?按任意键结束!=S1.stacksize)/如果栈满,追加存储空间 S1.b。

    8、ase=(char *)realloc(S1.base,(S1.stacksize+STACKINCREMENT)*sizeof(char); if(!S1.base) 潣瑵?存储分配失败!; else S1.top=S1.base+S1.stacksize; S1.stacksize=S1.stacksize+STACKINCREMENT; *S1.top=e;S1.top=S1.top+1;/将元素压入栈中,指针上移 char GetTop1(SqStack1 &S1)/取栈顶元素 char e; if(S1.top=S1.base)cout=S2.stacksize)/栈满,追加存储空间。

    9、 S2.base=(float *)realloc(S2.base,(S2.stacksize+STACKINCREMENT)*sizeof(float); 晩?戮獡?潣瑵?存储分配失败!; else S2.top=S2.base+S2.stacksize; S2.stacksize=S2.stacksize+STACKINCREMENT; *S2.top=e;S2.top=S2.top+1;/将元素 e 入栈,指针上移 6 void DispStack2(SqStack2 &S2)/从栈底到栈顶依次输出各元素 float e,*p; if(S2.top=S2.base)coutch; c=c。

    10、h0; 7潣瑵?屜n对表达式求值的操作过程如下: =0) e=float(c-48); n+; if(n=1)t=e; else if(n1)t=t*10+e; c=chs+; if(n=-1) e=float(c-48); t=t+e/10; 8c=chs+; if(c=.) n=-1; c=chs+; if(c=0&c9) Push2(S2,t); cout:/栈顶元素优先级高,则退栈并将运算结果入栈 p1=Pop2(S2); p2=Pop2(S2); ch1=Pop1(S1); Push2(S2,Operate(p2,ch1,p1); cout;/否则,栈顶符号优先级高,返回? else。

    11、 if(n=*|n=/)/输入的符号为?、屜尯 if(m=)|m=*|m=/)return ;/栈顶元素为尩、?、/,此时栈顶符号优先 级高,返回? else return ;/否则,栈顶符号优先级高,返回? else 输入符号为其他/ #,此时优先级同,返回?元素为if(m=#)return=;/栈顶 ?否则,栈顶符号优先级高else return ;/,返回 theta,floatOperate(float float a,char b)/运算函数 10 float tmp=0; if (theta=+)tmp=a+b;/从运算符栈取出的符号为尫,则运算数栈的两元素相加,并 返回 else。

    12、 if(theta=-)tmp=a-b;/从运算符栈取出的符号为?,则运算数栈的两元素相减,并 返回 else if(theta=*)tmp=a*b;/从运算符栈取出的符号为?,则运算数栈的两元素相乘,并 返回 else if(theta=/) /从运算符栈取出的符号为屜尯,则运算数栈的两元素相除,并 返回 if(b=0) cout表达式出错!除数不能为 0!n; else tmp=a/b; return tmp; 五、运行与测试 第六章 总结与心得 数据结构的研究不仅涉及到计算机硬件的研究,而且和计算机软件的研究有着更密切的关系, 无论是编译程序还是操作系统,都涉及到数据元素在存储器中的分配。

    13、问题。在研究信息检索时也必 须考虑如何组织数据,以便使查找和存取数据元素更为方便。 在课程设计中,应该力求算法简明易懂,而易于转换为上机程序;如果程序反复多次使用,则 应该尽可能选用快速的算法;如果待解决的问题数据量极大,机器的存储空间较小,则在编写算法 时应该考虑如何节省空间。以后在编写程序时就应该注意到所编写程序的时间复杂度,以及是否运 用了良好的算法,而不能只是像以前编写程序时单纯使用 C 语言的知识,要充分考虑程序的性能, 争取编写出更优良的程序来。 让我对数据结构有了更进一步的认识和了解,也让我知道,要想学好它要重在实践,理论与实 际应用相结合,提高了自己组织数据及编写大型程序的能力,培养了基本的、良好的程序设计技能 力。通过实际操作,我也发现我的好多不足之处: (1)用栈的结构来解决表达式的求值,首先要解决的问题是如何将人们习惯书写的表达式转换成计 11算机容易处理的表达式。开始有些茫然,后来通过结合课本和同学的帮助完成了该课题。 (2)对一些看似简单的东西掌握不够熟练,比如由于函数的调用参数问题不熟而造成了调试的困难。 对于语法的掌握也欠缺成熟,需要进一步掌握。 (3)栈的结构理解不够清晰,造成了设计程序时理不清头绪,需要对数据结构有更深层次的理解。 13。

    展开全文
  • 表达式求值设计实验报告

    千次阅读 2021-04-09 15:20:17
    课程设计题目表达式求值 一、问题描述与基本要求 利用栈,实现以下功能: 中缀表达式求值; 中缀表达式转后缀表达式; 后缀表达式求值。 假设用户输入的表达式均合法,且运算符只含+(加号)、-(减号)、*、/、...

    课程设计题目:表达式求值

    一、问题描述与基本要求

    利用栈,实现以下功能:

    1. 中缀表达式求值;
    2. 中缀表达式转后缀表达式;
    3. 后缀表达式求值。

    假设用户输入的表达式均合法,且运算符只含+(加号)、-(减号)、*/%(),允许浮点数(浮点数计算取模规定为向零取整后得到整数再计算取模)。

    二、概要设计

    1. 数据结构的设计

    我们利用栈来实现上述3个功能。具体原因见后文算法的设计

    2. 算法的设计

    2.1 表达式读入与预处理

    用户从键盘输入一个语法正确的中缀/后缀表达式,但格式可能并不标准,例如有多余的空格。另外,为了在后面计算表达式编码更方便,我想利用C++中的istringstream,所以要将表达式存储在字符串中,且数与数、数与符号、符号与符号之间都有空格,最后在字符串末尾加上#(原因见下)。

    用length表示输入的中缀表达式字符串长度,则

    时间复杂度空间复杂度
    O ( l e n g t h ) O(length) O(length) O ( l e n g t h ) O(length) O(length)

    2.2 计算中缀表达式

    先定义运算符的优先级。注意运算符在栈内和栈外的优先级是不同的,这是为了实现同优先级能从左往右计算。

    运算符+ -* / %()# ;
    isp(栈内优先级)35160
    icp(栈外优先级)24610

    定义#;,是为了后面统一处理表达式求值。

    接下来,我们定义两个栈:数值栈(num_stack)和符号栈(sgn_stack)。

    从左往右扫描中缀表达式,如果:

    1. 遇到数值就直接将它压入数值栈;
    2. 遇到运算符(记当前运算符为cur),检查符号栈的栈顶运算符的优先级
      1. 栈顶优先级小于cur,则直接压入cur
      2. 栈顶优先级大于cur,则弹出栈顶运算符和数值栈的两个数来计算,再把计算结果压入数值栈。重复直到栈顶运算符的优先级不再大于cur,再将cur压入。
      3. 栈顶优先级等于cur,从上面的运算符优先级的表格中我们可以知道这时候栈顶是左括号,cur是右括号,那么直接将这两个括号扔掉就好了。
    3. 最后数值栈里就只剩下一个数,就是整个中缀表达式的计算结果

    如果我们不在原本的中缀表达式后面加#;,那么还需要把符号栈中的运算符依次弹出来并计算,这无疑让编码更加繁琐更易出错。所以,不如在后面加上#;,并把优先级设计成最低(0),统一处理。

    伪代码如下

    for (从左到右扫描中缀表达式)
        if (cur == 数值)
            num_stack.push(cur)
        else // cur == 运算符
            while (isp(sgn_stack.top()) > icp(cur))
                b = num_stack.top(), num_stack.pop()
                a = num_stack.top(), num_stack.pop()
                用 sgn_stack.top() 计算 a 和 b,结果存到 c
                num_stack.push(c)
            sgn_stack.push(cur)
    

    用n表示输入的中缀表达式中运算符个数,则

    时间复杂度空间复杂度
    O ( n ) O(n) O(n) O ( n ) O(n) O(n)

    2.3 中缀表达式转后缀表达式

    我们只需要一个符号栈(sgn_stack)就够了。

    从左往右扫描中缀表达式,如果:

    1. 遇到数值就直接将它输出;
    2. 遇到运算符(记当前运算符为cur),检查符号栈的栈顶运算符的优先级
      1. 栈顶优先级小于cur,则直接压入cur
      2. 栈顶优先级大于cur,则弹出栈顶运算符并输出。重复直到栈顶运算符的优先级不再大于cur,再将cur压入。
      3. 栈顶优先级等于cur,从上面的运算符优先级的表格中我们可以知道这时候栈顶是左括号,cur是右括号,那么直接将这两个括号扔掉就好了,因为后缀表达式不需要括号。

    同样,这里在原来的中缀表达式后加上#;会更方便。

    后缀表达式并不需要在最后面也加上#;(因为它的计算和编码已经够简单了)。当然,加上也没问题。

    伪代码如下

    for (从左到右扫描中缀表达式)
        if (cur == 数值)
            输出 cur
        else // cur == 运算符
            while (isp(sgn_stack.top()) > icp(cur))
                输出 sgn_stack.top() sgn_stack.pop()
            sgn_stack.push(cur)
    

    用length表示输入的中缀表达式字符串长度,则

    时间复杂度空间复杂度
    O ( l e n g t h ) O(length) O(length) O ( l e n g t h ) O(length) O(length)

    2.4 计算后缀表达式

    后缀表达式的计算就简单了:遇数压栈,遇符就弹两个数来算。

    for (从左到右扫描后缀表达式)
        if (cur == 数值)
            num_stack.push(cur)
        else // cur == 运算符
            b = num_stack.top(), num_stack.pop()
            a = num_stack.top(), num_stack.pop()
            用 cur 计算 a 和 b,结果存到 c
            num_stack.push(c)
    

    用n表示输入的中缀表达式中运算符个数,则

    时间复杂度空间复杂度
    O ( n ) O(n) O(n) O ( n ) O(n) O(n)

    三、详细设计

    1. 每个函数

    1. 表达式读入与预处理:详见string _read_expression()
    2. 计算中缀表达式:详见double infix_expression_calc(string infexp)
    3. 中缀表达式转后缀表达式:string infix_expression_to_postfix_expression(string infexp)
    4. 计算后缀表达式double postfix_expression_calc(string posexp = _read_expression())

    2. 设计主函数

    主函数主要包括对设计的函数的测试。

    四、运行与测试

    1. 测试环境

    运行环境:Windows 20H2, i7-9750H @ 2.60GHz, 16GB RAM

    编译器:g++ (gcc version 8.1.0 (x86_64-posix-seh-rev0, Built by MinGW-W64 project))

    编译命令:-g

    运行终端:cmd

    2. 在调试程序的过程中遇到的问题与解决方案

    暂未发现异常。

    3. 设计的测试数据与测试结果

    测试1(测试表达式读入与预处理)

    样例1

         1+2   * (  3 -  (4-5)    /6  )  
    

    测试2(测试计算中缀表达式)

    样例2

    1+2*(3-(4-5)/6)

    样例3

    1.23+4.56

    测试3(测试中缀表达式转后缀表达式)

    样例4

    1+2*(3-(4-5)/6)

    样例5

    1.23+4.56

    测试4(测试计算后缀表达式)

    样例6

    1 2 3 4 5 - 6 / - * +

    样例7

    1.23 4.56 +

    4. 程序清单及运行结果

    #include "MyStack.h" // 数据结构老师要求自己写栈,用STL的stack也可
    #include <cstring>
    #include <iostream>
    #include <sstream>
    #include <string>
    #include <vector>
    using namespace std;
    
    string _read_expression();
    double infix_expression_calc(string infexp = _read_expression());
    string infix_expression_to_postfix_expression(string infexp = _read_expression());
    double postfix_expression_calc(string posexp = _read_expression());
    
    int main()
    {
        /* test read */
        // istringstream iss(_read_expression());
        // cout << "length: " << iss.str().length() << "\n";
        // char s[20];
        // while (iss >> s) cout << s << "\n";
    
        /* test infix_expression_calc */
        // cout << infix_expression_calc(_read_expression());
    
        /* test infexp to posexp */
        // cout << infix_expression_to_postfix_expression();
    
        /* test postfix_expression_calc */
        // cout << postfix_expression_calc(_read_expression());
    
        return 0;
    }
    
    inline int _check_ch_type(const char &ch)
    {
        if (ch >= '0' && ch <= '9' || ch == '.') return 1; // number
        if (ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '%' ||
            ch == '(' || ch == ')')
            return 2;            // sign
        if (ch == ' ') return 0; // space
        return -1;               // illegal character
    }
    
    string _read_expression()
    {
        string src; getline(cin, src);
        int pre = 0;
        vector<char> exp;
        for (int i = 0; i < src.length(); i++)
        {
            int chk = _check_ch_type(src[i]);
            if (chk == -1) throw "illegal expression";
            if (chk == 0 && exp.back() == ' ') continue;
            if (pre * chk >= 2) exp.push_back(' ');
            exp.push_back(src[i]);
            pre = chk;
        }
        exp.push_back(' '); exp.push_back('#'); exp.push_back('\0');
        return string(exp.begin(), exp.end());
    }
    
    double _string_to_double(char *s)
    {
        int cnt = -100000000;
        int len = strlen(s);
        double x = 0;
        for (int i = 0; i < len; i++, cnt++)
            if (s[i] == '.') cnt = -1;
            else x = x * 10 + s[i] - '0';
        double t = 1;
        while (cnt-- > 0) t *= 10;
        return x / t;
    }
    
    int _get_isp(char ch)
    {
        if (ch == '+' || ch == '-') return 3;
        if (ch == '*' || ch == '/' || ch == '%') return 5;
        if (ch == '(') return 1;
        if (ch == ')') return 6;
        if (ch == '#' || ch == ';') return 0;
        return -1;
    }
    int _get_icp(char ch)
    {
        if (ch == '+' || ch == '-') return 2;
        if (ch == '*' || ch == '/' || ch == '%') return 4;
        if (ch == '(') return 6;
        if (ch == ')') return 1;
        if (ch == '#' || ch == ';') return 0;
        return -1;
    }
    
    double _calc(double a, char sgn, double b)
    {
        switch (sgn)
        {
        case '+': return a + b;
        case '-': return a - b;
        case '*': return a * b;
        case '/': return a / b;
        case '%': return (long long)a % (long long)b;
        default: throw "illegal sign";
        }
    }
    
    double infix_expression_calc(string infexp)
    {
        istringstream is(infexp);
        Stack<double> num_stack;
        Stack<char> sgn_stack;
        char res[20];
        while (is >> res)
        {
            if (res[0] >= '0' && res[0] <= '9')
                num_stack.push(_string_to_double(res));
            else
            {
                int _icp = _get_icp(res[0]);
                while (!sgn_stack.empty() && _get_isp(sgn_stack.top()) > _icp)
                {
                    double b = num_stack.top(); num_stack.pop();
                    double a = num_stack.top(); num_stack.pop();
                    num_stack.push(_calc(a, sgn_stack.top(), b));
                    sgn_stack.pop();
                }
                if (!sgn_stack.empty() && _get_isp(sgn_stack.top()) == _icp)
                {
                    sgn_stack.pop();
                    continue;
                }
                sgn_stack.push(res[0]);
            }
        }
        return num_stack.top();
    }
    
    string infix_expression_to_postfix_expression(string infexp)
    {
        vector<char> posexp;
        Stack<char> sgn_stack;
        char buffer[20]; int bufcnt = 0;
        for (int i = 0; i < infexp.length(); i++)
        {
            char &cur = infexp[i];
            if (cur == ' ')
            {
                if (bufcnt)
                {
                    for (int j = 0; j < bufcnt; j++) posexp.push_back(buffer[j]);
                    posexp.push_back(' ');
                    bufcnt = 0;
                }
                continue;
            }
            if (cur >= '0' && cur <= '9' || cur == '.') 
                buffer[bufcnt++] = cur;
            else
            {
                int _icp = _get_icp(cur);
                while (!sgn_stack.empty() && _get_isp(sgn_stack.top()) > _icp)
                {
                    posexp.push_back(sgn_stack.top());
                    posexp.push_back(' ');
                    sgn_stack.pop();
                }
                if (!sgn_stack.empty() && _get_isp(sgn_stack.top()) == _icp)
                {
                    sgn_stack.pop();
                    continue;
                }
                sgn_stack.push(cur);
            }
        }
        posexp.push_back('#'); posexp.push_back('\0');
        return string(posexp.begin(), posexp.end());
    }
    
    double postfix_expression_calc(string posexp)
    {
        istringstream is(posexp);
        Stack<double> num_stack;
        char res[20];
        while (is >> res)
        {
            if (_check_ch_type(res[0]) < 0) break;
            if (res[0] >= '0' && res[0] <= '9')
                num_stack.push(_string_to_double(res));
            else
            {
                double b = num_stack.top(); num_stack.pop();
                double a = num_stack.top(); num_stack.pop();
                num_stack.push(_calc(a, res[0], b));
            }
        }
        return num_stack.top();
    }
    
    // MyStack.h
    
    template <typename T>
    struct Node {
        T data;
        Node *next;
    };
    
    template <typename T>
    class Stack {
    public:
        Stack() {}
        ~Stack() { for (Node<T> *tmp; _top != nullptr;) { tmp = _top; _top = _top->next; delete tmp; } }
        void push(T x) { _top = new Node<T>{x, _top}; }
        void pop() { Node<T> *tmp = _top; _top = _top->next; delete tmp; }
        T top() { return _top->data; }
        bool empty() { return _top == nullptr; }
    
    private:
        Node<T> *_top = nullptr;
    };
    

    样例1(符合预期)

    D:\OneDrive - mail2.sysu.edu.cn\MyDocuments\code\DSA\week07\ex3>main
    1+2   * (  3 -  (4-5)    /6  )
    length: 31
    1
    +
    2
    *
    (
    3
    -
    (
    4
    -
    5
    )
    /
    6
    )
    #
    
    

    样例2(符合预期)

    D:\OneDrive - mail2.sysu.edu.cn\MyDocuments\code\DSA\week07\ex3>main
    1+2*(3-(4-5)/6)
    7.33333

    样例3(符合预期)

    D:\OneDrive - mail2.sysu.edu.cn\MyDocuments\code\DSA\week07\ex3>main
    1.23+4.56
    5.79

    样例4(符合预期)

    D:\OneDrive - mail2.sysu.edu.cn\MyDocuments\code\DSA\week07\ex3>main
    1+2*(3-(4-5)/6)
    1 2 3 4 5 - 6 / - * + #

    样例5(符合预期)

    D:\OneDrive - mail2.sysu.edu.cn\MyDocuments\code\DSA\week07\ex3>main
    1.23+4.56
    1.23 4.56 + #

    样例6(符合预期)

    D:\OneDrive - mail2.sysu.edu.cn\MyDocuments\code\DSA\week07\ex3>main
    1 2 3 4 5 - 6 / - * +
    7.33333

    样例7(符合预期)

    D:\OneDrive - mail2.sysu.edu.cn\MyDocuments\code\DSA\week07\ex3>main
    1.23 4.56 +
    5.79

    五、参考资料

    1. 王红梅, 胡明, 王涛. 数据结构(C++版)[M]. 2 版. 清华大学出版社, 2011.
    2. 王红梅, 胡明, 王涛. 数据机构(C++版)学习辅导与实验指导[M]. 2 版. 清华大学出版社, 2011.
    展开全文
  • 实验题目表达式求值2. 实验目的:熟悉栈与队列3. 实验内容:话说令狐冲只告诉东方不败:“东方姑娘你会永远活在我的心中。”东方姑娘听了那是万念俱灰啊,精通算术的东方姑娘一时想不开,抛给令狐冲一个表达式,...

    表达式求值实验报告

    李一鹏 PB12001076 数学系

    1. 实验题目:表达式求值

    2. 实验目的:熟悉栈与队列

    3. 实验内容:

    话说令狐冲只告诉东方不败:“东方姑娘你会永远活在我的心中。”东方姑娘听了那是万念俱灰啊,精通算术的东方姑娘一时想不开,抛给令狐冲一个表达式,说:“这个表达式你要是不能在一秒内给我把值求出来我就要坠入悬崖!”令狐冲一看事态不对,马上发动辟邪剑法之求助观众!

    观众们,你们又不是不知道令狐冲的那个笨,东方姑娘的生命可以说是掌握在你们的手中了,喜欢她就99她吧!

    4. 算法分析:

    本算法采用了链表来储存表达式,加入了指数运算和函数还有常数π。由于指数运算是右结合,本算法先全部储存表达式再优先级一个个运算。对于函数和括号,本算法用了递归,遇到右括号即返回,把表达式的直接求解operate()转化成了无括号无函数表达式的求解calculate()。

    5. 程序清单:

    #include

    #include

    #include

    #include

    #define new1 (no*)malloc(sizeof(no))

    #define deletenode p2->prec=p1->prec;free(p1);p1=p2->prec;p1->next=p2

    #define error1 p1=head;p2=head-> next;if(p2){while(p2!=r){free(p1);p1=p2;p2=p2->next;}free(p1);p2->ope=1;return p2;}else{p1->ope=1;return p1;}

    #define fun(a,b,c)

    展开全文
  • 用栈进行表达式求值

    2020-12-22 01:05:54
    我们今天继续看一下,如何使用栈完成标准的四则混合运算表达式求值。不同于后缀表达式,遇到一个运算符就可以直接从栈里取两个数进行运算。在标准的四则混合运算表达式中(或者我们称之为中缀表达式),遇到一个操作符...

    上一节课,我们介绍了栈,并且在习题里使用栈计算了后缀表达式(最后一道题,这道题一定要先完成。如果那道题做不出来,这节课的内容就更加难以理解)。

    我们今天继续看一下,如何使用栈完成标准的四则混合运算表达式求值。

    不同于后缀表达式,遇到一个运算符就可以直接从栈里取两个数进行运算。在标准的四则混合运算表达式中(或者我们称之为中缀表达式),遇到一个操作符是不能直接计算的,因为计算的顺序要取决于后面的运算符。多举几个例子,大家就能明白了。由于加和减是相同的运算优先级,乘和除是相同的运算优先级,我们就只用加和乘来举例就可以了。

    我们像计算后缀表达式一样,引入一个操作数栈。由于后缀表达式不用缓存 +-*/ 这些操作符,所以一个操作数栈就够了。但是,中缀表达式的计算是要用到操作符的缓存的,所以,我们还要再引入一个操作符栈,专门存储各个操作符。

    第一个例子:a + b * c,我们从前向后扫描,遇到a,压到操作数栈里,遇到 + ,压到操作符栈里,下一个是 b,此时,我们是不能像后缀表达式求值那样,直接计算 a + b,然后压栈的。因为我们不确定,b 是否会先参与后面的运算,所以我们只能把 b 先压栈,继续向后扫描。看到 * 以后,再把 * 压到操作符栈里;看到 c 以后,也要把 c 先压栈,理由与 b 压栈相同。接下来,再往下扫描,就发现已经到了末尾了。那我们就可以放心地从操作符栈里取出顶上的操作符,在这个例子中,就是 *,然后再从操作数栈里取出两个操作数,就是 b 和 c,然后把b和c的积,不妨记为d,放到操作数栈里。接下来,再去看操作符栈里,还有一个 +,那就把 + 取出来,然后去操作数栈里取出 a 和 d,计算它们的和,这就是最终的结果了。

    第二个例子:a + b + c,我们从前向后扫描,遇到a,压到操作数栈里,遇到 + ,压到操作符栈里,下一个是 b,压到操作数栈里。再下一个,又是 + ,由于加法的结合律,我们知道,先把a + b 的结果计算出来,或者后计算,都不会影响最终的结果。所以我们就把能做的化简先做掉。就是说,在扫描到第二个操作符是 + 以后,我们就把第一个操作符取出来,再把两个操作数取出来,求和并且把和送到操作数栈里。接下来的过程与第一个例子是相同的,不再赘述了。

    通过这两个例子,我们看到,一个操作符究竟什么时候进行运算,并不取决于它前面的那个操作符是什么,而是取决于它后面的那个操作符是什么。更具体一点讲:如果后面的操作符的运算优化级比前面的操作符高,那么前面的操作符就必须延迟计算;如果后面的操作符优化级比前面的低或者相等,那么前面的操作符就可以进行计算了。上面这句话,非常重要,是我们这节课的核心。请多读几遍,结合上面的两个例子,务必想明白它。

    好了,理解了这个,就可以上代码了。

    先看 Stack的完整定义:

    class Stack {

    private ArrayList list;

    public Stack(int size) {

    this.list = new ArrayList(size);

    }

    public T getTop() {

    if (isEmpty())

    return null;

    return list.get(list.size() - 1);

    }

    public void push(T t) {

    this.list.add(t);

    }

    public T pop() {

    if (isEmpty())

    return null;

    return list.remove(list.size() - 1);

    }

    public boolean isEmpty() {

    return list.isEmpty();

    }

    }

    然后我们创建两个栈,一个是操作数栈,一个是操作符栈:

    public class StackExpression {

    public static void main(String args[]) throws IOException {

    TokenStream ts = new ExpressionTokenStream(System.in);

    Stack numbers = new Stack<>(100);

    Stack operators = new Stack<>(100);

    }

    }

    其中,TokenStream 是这节课里的课后作业:适配器模式

    按照上面分析的算法,如果遇到数字,就压栈到numbers里,如果遇到操作符,就要看前面一个的操作符的优先级是否比当前操作符高,如果前一个操作符高,那么执行前一个操作符的操作,如果是后面的高,那就只要把后面的操作符压栈即可:

    public class StackExpression {

    public static void main(String args[]) throws IOException {

    TokenStream ts = new ExpressionTokenStream(System.in);

    Stack numbers = new Stack<>(100);

    Stack operators = new Stack<>(100);

    while (ts.getToken().tokenType != Token.TokenType.NONE) {

    if (ts.getToken().tokenType == Token.TokenType.INT) {

    numbers.push((Integer)ts.getToken().value);

    ts.consumeToken();

    }

    else {

    if (operators.getTop() == null || preOrder( operators.getTop().tokenType, ts.getToken().tokenType) < 0) {

    operators.push(ts.getToken());

    ts.consumeToken();

    }

    else {

    binaryCalc(numbers, operators);

    operators.push(ts.getToken());

    ts.consumeToken();

    }

    }

    }

    while (!operators.isEmpty()) {

    binaryCalc(numbers, operators);

    }

    System.out.println("result is " + numbers.getTop());

    }

    private static void binaryCalc(Stack numbers, Stack operators) {

    int a = numbers.pop();

    int b = numbers.pop();

    Token oprt = operators.pop();

    int d = 0;

    if (oprt.tokenType == Token.TokenType.PLUS)

    d = b + a;

    else if (oprt.tokenType == Token.TokenType.MULT)

    d = a * b;

    else if (oprt.tokenType == Token.TokenType.MINUS)

    d = b - a;

    else if (oprt.tokenType == Token.TokenType.DIV)

    d = b / a;

    numbers.push(d);

    }

    private static int preOrder(Token.TokenType left, Token.TokenType right) {

    if (left == Token.TokenType.PLUS || left == Token.TokenType.MINUS) {

    if (right == Token.TokenType.MULT || right == Token.TokenType.DIV)

    return -1;

    else

    return 1;

    }

    else

    return 1;

    }

    }

    好了。我们的这个程序已经可以处理类似 a + b - c * d + e / f 这样的算式了。

    为了让大家看得更清楚,我用图把 a + b * c / d 的过程画一遍。

    首先,遇到 a ,把 a 送到操作数栈,遇到 + ,送到操作符栈:

    遇到 b,压栈

    遇到乘,由于乘的优先级高于加,所以,现在就什么也不做,只把乘号进栈:

    同样,遇到 c 把 c 进栈(此图略,请自己补上),再遇到 / ,由于除的优先级与 * 的优先级相同,所以,乘就可以先做了。这个动作是把乘号出栈,把c 和 b出栈,求 c * b的值,并且把这个值入栈。即:

    然后把 / 入栈,把 d 入栈:

    现在到了运算的结尾了。我们只需要把现在的栈里的内容从顶向下计算起来即可,先算除法:

    再算加法:

    但是,括号怎么办?

    可以这样想,在遇到形如 a * (b + c) 这样的形式的时候,左边的乘法是一定不能做的,我们只需要将左括号进栈即可。所以,我们可以把TokenStream里取得的左括号看做是一个优先级无穷大的运算符,它使得左方的运算符都不能提前进行计算。

    遇到右括号时,b + c 这个加法是可以进行运算的了,所以可以把右括号看作是一个优先级无穷小的运算符,它会使得操作符栈上的所有运算符都出栈并执行计算,直到遇到左括号。遇到左括号以后,只需要把左括号从栈里弹出来,然后让它和右括号一起狗带即可(这就是括号匹配啊,同学们~)。由于括号内的计算都已经完成了,结果是一个整数,我们已经在计算的过程中把这个整数放到操作数栈里了。所以整个括号内的求值就完成了。

    好了。今天的课程很短,但是比较难理解,尤其是,今天的程序都依赖于本周前边的课程。请务必先完成本周前边的课程再来看这节课。

    演示一下,我的完整版的效果:

    好了。今天的课程就到这里了。

    今天的作业:

    把括号的逻辑补充好。使用栈完成完整的表达式求值。

    我的完整的代码上传到小密圈《进击的Java新人》里了,圈里的同学请先不要直接看代码,请一定自己动动脑筋,争取把这个过程想明白。尤其是要对照着后缀表达式求值的程序去看,体会一下这两个题目有什么相关性。

    好了。到这里为止,第二周的课程就全部结束了。

    总结一下:

    在Java中的设计模式:适配与装饰 这一课中,我们学会了如何把标准输入上的字符处理成各种Token

    数据结构(一):栈 这一课中,我们学会了栈这种数据结构,并且使用栈处理了括号匹配,以及后缀表达式求值。有了这两节课的基础,在本节课中,我们写出了完整的表达式求值的程序 。

    本周课程到这里就结束了。下一周,我会介绍另外一种方法进行表达式求值。那就是使用自顶向下的文法分析来处理表达式。这将为我们稍稍揭开编译器工作方式的一点奥秘。谢谢你们关注我的课程,各位读者,圣诞快乐~

    展开全文
  • 表达式求值(数据结构栈,c语言版)

    千次阅读 多人点赞 2021-07-24 20:23:38
    严蔚敏数据结构(C语言版)第2版,数据结构栈,课本第79页表达式求值实验。
  • 匿名用户1级2016-09-22 回答算术表达式求值演示一、概述数据结构课程设计,要求...在这次的课程设计中我选择的题目是算术表达式求值演示。表达式计算是实现程序设计语言的基本问题之一,也是栈的应用的一个典型例子...
  • 表达式求值系列题目

    2021-11-24 14:34:45
    leetcode 224 基本计算器 题目描述 leetcode224 题目分析 代码实现
  • 表达式求值其实是《数据结构》课程里一个基本且重要的问题之一,一般作为 “栈” 的应用来提出。 问题的关键就是需要按照人们通常理解的运算符的优先级来进行计算,而在计算过程中的临时结果则用 栈 来存储。 为此...
  • 算术表达式求值的实现院(系):*****专 业:*****班 级:*****学 号:*****姓 名:*****指导教师:*****目 录1 课程设计介绍11.1 课程设计内容11.2 课程设计要求12 课程设计原理22.1 课设题目粗略分析22.2 原理图介绍...
  • 表达式求值重点问题探讨 注:一、二部分是精髓也是基础,三及其后部分是一些变形和应用,希望你能从一、二部分获得经验和技巧,充分运用到后面问题的思考中。 先从一个经典的问题谈起, 一、24点问题 *你有 4 张写有...
  • 完成不含括号的整数的加减乘除四则运算的长算式(含两个运算符)的求值,其中所有的中间结果均为整数。输入一行不含括号 的加减乘除四则运算的长算式,"="表示输入结束。输出有三种情况: 1、如果能够进行运算则输出...
  • 下面先实现最基本的加减乘除(重点分析如何实现字符串读入中多位数的处理方式)由于实现方法有三种,一个是利用两个栈实现的代码,一个是中缀转后缀,一个是顺序栈实现。本文先用两个栈实现 在这里插入代码片 #...
  • 基于栈的后缀算术表达式求值

    千次阅读 2019-05-14 14:23:27
    题目描述:输入一个中缀算术表达式,将其转换为后缀表达式,然后对后缀表达式进行求值。运算符包括+ - * / =,参与运算的为小于10的自然数。 功能要求及说明: (1) 输入要求:可输入多组测试数据,每组数据对应一个...
  • 表达式求值的代码和思路

    千次阅读 2018-11-08 19:29:55
    #表达式求值 今天给大家带来一道比较难的题,表达式求值 题目 题目描述: 一个可以带括号的小学算术四则运算表达式。 输入格式: 一行,一个四则运算表达式。’‘表示乘法,’/'表示除法 输出格式: 一行,该...
  • 后缀表达式求值

    2020-12-14 16:19:35
    一、题目 输入一行表示后缀表达式,数与数之间一定有空格隔开(可能不只一个空格),最后输入@表示输入结束 二、分析 后缀表达式,特点为运算符在两个操作数后,所可以用栈来实现。 用一个栈来存储数,遇到运算符...
  • 373-时间复杂度(表达式求值

    千次阅读 2018-05-04 15:56:19
    题目链接:373-时间复杂度 在 ACM 里面,计算复杂度是一项非常重要的事情,常见的复杂度格式有三种: O(n) O(lg(n)) O(sqrt(n)) 一个算法往往有多种解法,每种解法的复杂度有上述常见的的复杂度组合成,例如...
  • 课程设计题目:算术表达式的求解 设计要求: 设计一个算术表达式求解的程序,能重复地执行以下操作,直到选择退出为止。 程序功能包括: (1)从键盘输入要求解的算术表达式表达式必须包括加减乘除和括号); (2...
  • 【练习】算术表达式求值

    千次阅读 2017-11-19 20:42:27
    在编译系统中都必须提供算术表达式求值功能,也是通过栈来实现。下面介绍一个简单的算术表达式求值功能的实现,只能对整数的四则混合运算表达式求值
  • C++ 数据结构 算数表达式求值——栈存储

    千次阅读 多人点赞 2020-04-06 23:14:44
    1、题目:算术表达式求值 2、要求: (1)正确解释表达式; (2)符合四则运算规则: (3)先乘除、后加减; (4)从左到右运算; (5)先括号内,后括号外; (6)输出最后的计算结果。 二、问题描述 1、对一个合法...
  • 数据结构算术表达式求值算法沈阳航空航天大学课 程 设 计 报 告课程设计名称:数据结构课程设计课程设计题目:算术表达式求值算法院(系):计算机学院专 业:计算机科学与技术班 级:学 号:姓 名:指导教师:丁国辉...
  • 数据结构课程设计(二)---算术表达式求值

    千次阅读 多人点赞 2020-06-22 11:22:30
    编程利用“算符优先法”算术表达式。 要求: (1) 从键盘或文件读入一个合法的算术表达式,输出相应的后缀表达式。后缀表达式中,数据与数据之间加分隔符; (2) 输出正确的计算结果,保留两位小数点; (3...
  • C语言波兰表达式求值

    2020-04-14 23:10:27
    利用一个操作数栈,从表达式末尾遍历,遇到数字则入栈,遇到运算符则依次出栈两个数进行运算,然后将结果入栈。这样扫描完整个表达式之后,栈中剩下的即为表达式
  • 《数据结构与算法》实验:线性结构及其应用——算术表达式求值 《数据结构与算法》实验:树型结构的建立与遍历 《数据结构与算法》实验:图结构的建立与搜索 《数据结构与算法》实验:查找结构的实验比较——二叉...
  • 我们可以发现其实这都是表达式求值问题,只不过题目表达式形式不一,是只有+,-;还是+,-,*,\,^都有;甚至包括(),还有的可能有自定义计算。 那么对这类表达式求值问题有没有一个统一的方法求值呢?是有滴!...
  • 利用栈求表达式,可供小学生作业,并能给出分数
  • 根据 逆波兰表示法,求表达式。 有效的运算符包括 +, -, *, / 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。 说明: 整数除法只保留整数部分。 给定逆波兰表达式总是有效的。换句话说,表达式总会...
  • 表达式求值问题: 表达式求值是程序设计语言编译中一个最基本的问题。它的实现也需要栈的运用。下面介绍的算法是由运算符优先级确定运算顺序的对表达式求值算法。 21:36:29 一个表达式是由运算数(operand)、运算符...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 29,652
精华内容 11,860
关键字:

表达式求值题目分析