首页 > 其他分享 >2024.4.15 学习数理结构“栈”后的四则运算

2024.4.15 学习数理结构“栈”后的四则运算

时间:2024-04-15 12:11:47浏览次数:35  
标签:字符 2024.4 ser int double 四则运算 char 15 stack

使用栈的四则运算

1.题目描述

用顺序栈和算符优先法求解表达式的值

2.任务定义和问题分析

四则运算基本运要通过算法优先级和后缀表达式的思想完成,应当由以下功能:
(1)可以先求解后缀表达式。然后再求值,也可以一并完成。
(2)表达式中的运算为加、减、乘、除四种,包括括号,参与运算的数字为个位数。
(3)要考虑除法运算除数为零的特殊情况,有相应的处理措施。
(4)能检测括号不匹配的情况。
(5)建立操作符栈和操作数栈,编写相应的进栈和出栈函数。
(6)要有任务分解逐步求精的意识,合理划分子函数实现单个功能。
(7)可以进行多次表达式的计算,而不是运算一次就结束。
(7)操作数可以为多位整数,或者小数。例如123(2.3+89.5)。
(8)可增加阶乘运算,例如3!+4
2/(1-5)。
(9)可增加指数运算,例如4*2/(1-5)^2。

分析问题:分析四则运算需要用顺序栈来完成计算。因为我们只在一端输入输出,使用顺序栈使用数组下标进行进栈出栈操作更方便快捷,且由于一次性分配了足够的内存,时间处理上更快。而为防止栈的溢出,我使用动态分配的顺序栈。各具体功能设计为子函数,方便调试和复用,同时程序结构清晰易读。

简单的逻辑结构:定义一个char类型的字符组作为字符栈,一个int类型的数组作为数字栈。各子函数中,根据具体情形进行异常处理并给出提示。(像输入错误格式的算术式时会给出恰当的提示)。

3.数据结构的选择和概要设计

一.为了实现上述程序功能,首先定义存储的字符的字符栈以及数字栈。

二.系统中的子函数及功能要求
程序中共有14个子函数,分别为:
①边将算术式转为后缀表达式边计算的函数option()
②寻找大数小数的函数find()
③进数字栈的函数input_number()
④判断数字栈是否满了的函数Fulli()
⑤判断字符栈是否满并存入一个字符的函数Storage()
⑥判断字符栈是否满的函数 fullc()
⑦将一个字符存入字符栈input_char()
⑧使用弹出的运算符的函数Operation_And_Storage()
⑨将一个数字出栈的函数output_number()
⑩进行实际运算的函数shuan()
⑪弹出字符的函数output_number()
⑫计算阶乘的函数jie()
⑬为字符栈增添空间的函数addstackc()
⑭为数字栈增添空间Addstacki()

各子函数具体介绍如下
(1)double option(char a[],char_stack b,int_stack c)
①输 入:无
②输 出:无
③返回值:输入错误的提示ERROR 或 计算的值
④功 能:边将算术式转为后缀表达式边计算

(2)double find(char a[],int *r,int i)
①输 入:无
②输 出:无
③返回值:输入错误的提示ERROR 或找到的数
④功 能:使四则运算可以计算小数和大于10的自然数

(3)void input_number(double a,int_stack c)
①输 入:无
②输 出:无
③返回值:无
④功 能:将一个数存入数字栈

(4)void fulli(int_stack c)
①输 入:无
②输 出:无
③返回值:无
④功 能:判断数字栈是否满了
(5)void Storage(char a,char_stack b)
①输 入:无
②输 出:无
③返回值:无
④功 能:判断字符栈是否满并存入一个字符
(6)void fullc(char_stack b)
①输 入:无
②输 出:无
③返回值:无
④功 能:判断字符栈是否满
(7)Void input_char(a,b)
①输 入:无
②输 出:无
③返回值:无
④功 能:将一个字符存入字符栈
(8)double Operation_And_Storage(char_stack b,int_stack c)
①输 入:无
②输 出:无
③返回值:输入错误的提示ERROR 或 1
④功 能:弹出两个数字栈,弹出一个字符栈,根据字符栈计算,就计算结果存入数字栈
(9)double output_number(int_stack c)
①输 入:无
②输 出:无
③返回值:出栈的数字
④功 能:将数字栈出一个栈
(10)double shuan(double a,double b,char c)
①输 入:无
②输 出:无
③返回值:计算的结果 或 输入错误的提示ERROR
④功 能:实际计算操作
(11)char out_char(char_stack b)
①输 入:无
②输 出:无
③返回值:弹出的字符
④功 能:将一个字符弹出字符栈
(12)double jie(int a)
①输 入:无
②输 出:无
③返回值:阶乘的值
④功 能:计算阶乘
(13)void addstackc(char_stack b)
①输 入:无
②输 出:无
③返回值:无
④功 能:为字符栈增添空间
(14)void addstacki(int_stack c)
①输 入:无
②输 出:无
③返回值:无
④功 能:为数字栈增添空间
三.主程序及各程序模块(函数)之间的层次(调用)关系

4.详细设计

(一)double option(char a[],char_stack b,int_stack c)
我将遇到的字符分为几大类,分别是数字,(,),+或-,*或/,!,^.7种情况。并根据算术优先顺序对每大类进行分类讨论。由于分类多但每个类别进行的操作都简单不适合用文字赘述,就看我的逻辑框架。
逻辑框架:


流程图:

代码与注释:




(二)double find(char a[],int (*)r,int i)(由于博客园不显示我的指针符*,所以我只好加了个括号框起来,你自己写不要框)

通过循环判断大数或小数是多少。一直取a[i]的下一个字符,如果是数字就让本来的数字10加上该数字成为新的本来数字,直到下一个不是数字。如果这个不是数字的字符恰好是“.”小数点,就一直取a[i]的下一个字符,让本来数字加上该数字pow(10,-w),w为小数点后的几位。直到下次不是数字。

5.调试分析

问题(1):
问题概述:一开始我的主要逻辑程序全部写在一起,像缠绕在一起的数据线,杂乱无章。当我想要完成进阶任务时,我发现自己的程序不具有可维护性和提升性。
解决过程:我先画了个简单的思维导图,将重复的部分写成专门的子函数,将自己的程序,重新写了一次。
问题(2):
问题概述:在遇到‘)’后即使后面还有未输出的字符,但我的字符栈就不输出也不输入了,而且我的检查程序还没有报错ERROR
解决过程:我用printf将循环中每个字符栈的字符以及其拥有的字符个数打印出来,进行调试。发现‘)’后字符栈的下一个进栈点错误的出现在-1处,由于我的判断语句只判断了前一个字符的种类是什么以及是不是在0处,没有考虑会出现小于0的情况。所以经过‘)’后就不进入判断语句。就造成了没有报错但输出有错的情况。
解决方法:字符栈本不可能在-1处。我发现在子函数中我已经x-1了,但主函数的循环里我又-1,两次操作重复了,于是出现了负数。所以我删去了循环的-1。

6.测试结果和分析


7. 源代码(完成了去年说的要改进的计划,去年没学栈但老师让我们写四则运算的苦逼场景还历历在目,但在坚持2天后还真写了一个四则运算的程序(虽然他不能计算括号,阶乘,次幂但它可以做到理论上无限的加减乘除,支持小数大数),收获感满满,就写了一个不太成熟的博客并说之后会完善他,今天就完善了。)

点击查看代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define ERROR 3.14159
typedef struct stack1 {  //字符栈ser
    char *ser;//存储算数符号
    int x;//指向栈位置
    int max;//表示这个栈最大存储的位置
} stack1,*char_stack;

typedef struct stack2 {  //数字栈seri
    double *ser;//存储算数的数字
    int x;//指向栈位置
    int max;//表示这个栈最大存储的位置
} stack2,*int_stack;




double option(char a[],char_stack b,int_stack c);//进出栈的计算顺序
double shuan(double a,double b,char c);//实际计算操作
void Storage(char a,char_stack b);//存入数字栈
double Operation_And_Storage(char_stack b,int_stack c);//弹出两个数字栈,弹出一个字符栈,根据字符栈计算,就计算结果存入数字栈
void input_number(double a,int_stack c);//进栈 数栈
double output_number(int_stack c);//出栈 数栈
void fulli(int_stack c);//判断数栈是否满
void addstacki(int_stack c);//添加额外空间

void input_char(char a,char_stack b);//进栈 字符栈
char out_char(char_stack b);//出栈 字符栈
void fullc(char_stack b);//判断字符栈是否满
void addstackc(char_stack b);//添加字符栈额外空间
double jie(int a);//计算阶乘
double find(char a[],int *r,int i);//找到大数或小数

int main()//主函数
{
    char_stack charstack = (char_stack)malloc(sizeof(stack1));//初始化一个字符栈,一个数字栈
    charstack->ser=(char*)malloc(100*sizeof(char));
    charstack->x=0;
    charstack->max=100;

    int_stack intstack =(int_stack)malloc(sizeof(stack2));
    intstack->ser=(double*)malloc(100*sizeof(double));
    intstack->x=0;
    intstack->max=100;

    char a[100];
    int count_times;

    printf("请输入你想进行几次运算(少于等于十次):");
    while(1)
    {
        scanf("%d",&count_times);
        if(count_times<=10&&count_times>=0)
        {
            break;
        }
        printf("请输入你想进行几次运算(少于等于十次):");
    }
     getchar();
    int i;
    double result;
    for(i=0; i<count_times; i++) {
        printf("请输入要计算的式子(如果要用括号记得用英文的喔):");
        fgets(a,sizeof(a),stdin);
        result=option(a,charstack,intstack);
        charstack->x=0;
         intstack->x=0;
        if(result==ERROR)
        {
             printf("输入的算术式不符合格式\n");

        }
        else
            {
                printf("结果是:\n");
           printf("%.2f\n",result);
            }
    }
    free(charstack->ser);
    free(intstack->ser);
     free(charstack);
    free(intstack);
    return 0;
}

double find(char a[],int *r,int i)//存入大数或小数
{
    int j=i+1;
    int w=0;
    double asum=(double)a[i]-48;
    for(;a[j]>=48&&a[j]<=57;j++)
    {
        asum=asum*10+((double)a[j]-48);
    }
    if(a[j]=='.')
    {
        j++;
        w--;
        if(!(a[j]>=48&&a[j]<=57))
        {
            return ERROR;
        }
        for(;a[j]>=48&&a[j]<=57;j++,w--)
    {
        asum+=((double)a[j]-48)*pow(10,w);
    }
    }
    *r=j-1;
    return asum;
}

double jie(int a)//计算阶乘
{
    if(a==0||a==1)
    {
        return 1;
    }
    double i,sum=1;
    for(i=1;i<=a;i++)
    {
        sum*=i;
    }
    return sum;
}

//
void addstackc(char_stack b) //添加字符栈额外空间
{
 b->ser=(char *)realloc(b->ser,(b->max+5)*sizeof(char));
b->max+=5;
}

void fullc(char_stack b)//判断字符栈是否满
{
 if(b->x==b->max-2)
 {
     addstackc(b);
 }
}

char out_char(char_stack b)//出栈 字符栈
{
    b->x--;
    return b->ser[b->x];
}

void input_char(char a,char_stack b)//进栈 字符栈
{
    b->ser[b->x]=a;
    b->x++;
}

double output_number(int_stack c)//出栈 数栈
{
    c->x--;
    return c->ser[c->x];
}
void fulli(int_stack c)//判断数栈是否满
{
    if(c->x==c->max-2)
    {
       addstacki(c);
    }
}

void addstacki(int_stack c)//添加数栈额外空间
{
    c->ser=(double *)realloc(c->ser,(c->max+5)*sizeof(double));
    c->max+=5;
}
void input_number(double a,int_stack c)//进栈 数栈
{
    c->ser[c->x]=a;
    c->x++;
}
//
double shuan(double a,double b,char c)//实际计算操作
{
    if(c=='+')
    {
        return a+b;
    }
    else if(c=='-')
    {
        return a-b;
    }
    else if(c=='*')
    {
        return a*b;
    }
    else if(c=='/'&&b==0)
    {
        return ERROR;
    }
    else if(c=='/'&&b!=0)
    {
        return a/b;
    }
    else if(c=='^')
    {
        return pow(a,b);
    }
    else
    {
        return ERROR;
    }

}
void Storage(char a,char_stack b)//存入字符栈
{
   fullc(b);
    input_char(a,b);
}
double Operation_And_Storage(char_stack b,int_stack c)//弹出两个数字栈,弹出一个字符栈,根据字符栈计算,就计算结果存入数字栈
{
    double p,q,n;
    char w;
    if(c->x==0)
    {
        return ERROR;
    } else
    {
        p=output_number(c);
    }
    if(c->x==0)
    {
        return ERROR;
    } else
    {
        q=output_number(c);
    }
    w=out_char(b);
    n=shuan(q,p,w);
    if(n==ERROR)
    {
        return ERROR;
    }
    input_number(n,c);
    return 1;
}

double option(char a[],char_stack b,int_stack c)//判断出栈还是入栈,并计算的基本逻辑
{
    int i,x,y;
    double w,num;
    for(i=0; a[i]!='\0'; i++) {
        if(a[i]>=48&&a[i]<=57) {
                fulli(c);
                num=(double)a[i]-48;
            if((a[i+1]>=48&&a[i+1]<=57)||(a[i+1]=='.'))    //若读取到数字
            {
                num=find(a,&i,i);
                if(num==ERROR) {
                    return ERROR;
                }
            }
           input_number(num,c);
        }
       else if(a[i]=='(')                         //若读取到(
        {
            Storage(a[i],b);
        }


        else if(a[i]=='+'||a[i]=='-')            //若读取到+或-
        {
            if(b->x==0||b->ser[b->x-1]=='(')
            {
                 Storage(a[i],b);
            }
            else if(b->ser[b->x-1]=='+'||b->ser[b->x-1]=='-'||b->ser[b->x-1]=='*'||b->ser[b->x-1]=='/'||b->ser[b->x-1]=='^')
            {
                if(Operation_And_Storage(b,c)==ERROR)
                {
                    return ERROR;
                }
                input_char(a[i],b);

            }
        }
        else if(a[i]=='*'||a[i]=='/')       //若读取到*或/
        {
            if(b->x==0||b->ser[b->x-1]=='('||b->ser[b->x-1]=='+'||b->ser[b->x-1]=='-')
            {
               Storage(a[i],b);
            }
             else if(b->ser[b->x-1]=='*'||b->ser[b->x-1]=='/'||b->ser[b->x-1]=='^')
            {
                 if(Operation_And_Storage(b,c)==ERROR)
                {
                    return ERROR;
                }
                input_char(a[i],b);
            }
        }
        else if(a[i]==')')       //若读取到)
        {
            int j=b->x-1;
            for(;j>=0&&b->ser[j]!='(';j--)
            {
                 if(Operation_And_Storage(b,c)==ERROR)
                {
                    return ERROR;
                }
            }
            if(j<0)
            {
                return  ERROR;
            }
            else
            {
               b->x--;
            }

        }
        else if(a[i]=='!')     //若读取到!
        {
            double q;
            int ex;
            q=output_number(c);
            if(q<0)
            {
                return ERROR;
            }
            ex=(int)q;
            if(ex!=q)
            {
                return ERROR;
            }
            q=jie(ex);
             input_number(q,c);
        }
        else if(a[i]=='^') //若读取到^
        {
             Storage(a[i],b);
        }
        else if(a[i]=='.')   //若读取到.
        {
            return ERROR;
        }
    }
    for(;b->x>0;)  //将字符栈依次出栈,并计算
    {

            if(Operation_And_Storage(b,c)==ERROR)
                {
                    return ERROR;
                }
    }
    if((c->x)>1)  //如果字符栈完全计算完了且数字栈还有2个及以上的数字
    {
        return ERROR;
    }
    else //字符栈完全计算完了且数字栈只有一个数字
    {
        w=output_number(c);
        return w;
    }
}


8.寄语

这次博客不是老师的任务,倒是给过去的自己一个交代吧。前方道阻且长啊,HURRY up!!

标签:字符,2024.4,ser,int,double,四则运算,char,15,stack
From: https://www.cnblogs.com/618907814lyy/p/18135481

相关文章

  • 函数式编程思想 VS 可变性理论 20240415
    函数式编程(FunctionalProgramming,FP)是一种编程范式,它将计算视为数学函数的求值,并避免使用程序状态以及易变对象。函数式编程的核心思想包括:不可变性(Immutability):在函数式编程中,数据是不变的。一旦创建了一个数据结构,就不能再改变它。所有的操作都会产生新的数据结构。纯......
  • 21/10/11 - 21/10/15 零碎知识记录
    1.pc端实现移动端拖动效果思路moveDown记录鼠标按下位置记录当前状态为按下拖动+moveUp记录当前状态为非拖动moseMove根据拖动状态,计算当前拖动距离判断左拖右拖边界值对元素进行移动修改鼠标按下位置,以便下次计算移动距离,不初始化会导致移动距离指数式增加,移......
  • 结对编程--四则运算
    前言按照结对编程的原则,我和小组另一个成员进行了结对编程。我们开发的结对项目是小学的四则运算生成器。具体来说,我们开发了一个程序,用于随机生成四则运算题目,供学生答题,并返回答案的正误。在讨论后,我们决定使用C++来开发这个控制台程序,因为C++具有优秀的计算功能,并且能够在......
  • LeetCode 面试经典150题---006
    玩了一天多,两天没写了,下次绝对不摆了(最多摆一天)。####42.接雨水给定n个非负整数表示每个宽度为1的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。n==height.length1<=n<=2*1040<=height[i]<=105不用头想都知道这个题肯定只能用线性复杂度做,至于怎......
  • python四则运算生成器
    合作伙伴:2252717在编程任务中,清晰地理解并规划设计思路是至关重要的。对于这个特定的四则运算题目生成器,目标是创建一个程序,能够随机生成包含两个运算符的数学题目,这些题目涉及100以内的数字,并确保所有生成的题目的答案都在0到100之间。以下是我在设计和实现这个程序时遵循的详细......
  • 2024.4.11(周四)进度
    做python大作业,但是没实现图形化界面importosM=15#校园景点数量INF=0x3f3f3f3fclassCampus:att=["","正门","科技楼","第一教学楼","基础教学楼","图书馆","北小门","宿舍区","西操场","学二食堂",&......
  • 2024.4.8(周一)进度
    完成需求文档并提交软件需求文档1.引言1.1编写目的本文档的目的是详细地介绍“人人帮扶”APP所包含的需求,以便客户能够确认产品的确切需求以及开发人员能够根据需求设计编码,以下叙述将结合文字描述、UML图等来描述“人人帮扶”APP的功能、性能、用户界面、运行环境、外部接口......
  • 2024.4.14
    2024.4.14【言念君子,温其如玉。】Sunday三月初六<theme=oi-"search"><BGM=Realms>模拟赛!!!P1274魔术数字游戏就摁模搜索就行,我是实在打不下去了。考试时200行白打了P1275魔板//2024.4.14//bywhite_ice#include<bits/stdc++.h>usingnamespacestd;#defin......
  • 结对编程--四则运算(Python)
    合作伙伴:2252720`importrandomdefgenerate_expression():operators=['+','-','×','÷']#可用的运算符operator=random.choice(operators)#随机选择一个运算符ifoperator=='+':num1=random.randint(0,100)#生成第一......
  • 结对编程--四则运算
    结对编程--四则运算(Python)合作伙伴:2252619前言按照结对编程的原则,我和小组另一个成员进行了两人进行了结对编程,我们开发的结对项目的是小学的四则运算,具体就是随机生成四则运算题目,供学生答题并返回正误。经过讨论,介于Python优秀的计算功能以及时间限制,我们将采用Python开发一......