1.0总结

news/2024/7/24 12:26:41 标签: c/c++

GitHub develop分支

团队:
盖嘉轩 031602211
许郁杨 031602240

1.0主要是描述一下程序本身,也就是代码和编码规范部分,完整的总结会在完善一些细节后再提交。其实原定是应该在13号提交这篇文章的,只是我写的部分出了点问题。。

其实因为两个人的时间安排问题,导致刚开始没办法常在网上交流,很多问题都是在电话里解决的,难道要把通话记录当证据吗。。总之先用文字阐述一下这个程序的实现过程。

  • 分工
  • 日程规划
  • 编程规范
  • 实现思路和遇到的困难
  • 代码(个人负责部分)
  • 提交记录

分工

一开始我们就确定了要使用多源文件编写。各个文件的功能分类是我提出方案,然后两个人再一起讨论确定下来的。最初的源文件是这样分类的:

文件名功能
head头文件
main初始界面
calculate计算器主体
fraction生成、计算分数
stack计算表达式

实际上这个分类是有点问题的,很多功能都集中在了个别文件里,只是这个问题写到了stack我们才发现,而且模块分类上也有很多毛病,这也导致了后面千奇百怪的bug。。这个后面会具体说。

最初的分工是这样的:我负责fraction和stack,队友负责其他部分。这也算是最后分工。

1.0的文件分类:

文件名功能
head头文件
main初始界面
generate生成表达式
fraction生成、计算分数
stack计算表达式
verify检验答案并输出

实现过程中,最初的calculate包括的功能比想象中的多得多。。编写时已经特地分流一些给其他文件了,还是显得有些臃肿,所以最后还是硬拆了一个文件出来。分工没什么变化。

功能模块的分类会在实现思路部分具体地说。


日程规划

不得不感叹一下两个人都很忙啊。。前期基本没时间做,差不多8号之后才开始写代码。

简单的日程规划:

此处输入图片的描述

最后。。嗯,晚了一天。。

不过,实际的情况是基本符合规划的。只是13号在测试时发现了一个大坑,填到了今天才勉强填好。


编程规范

编程规范是在模块分类后才一一确定下来的,不过由于变量超乎想象的多,所以变量命名有点混乱。

变量的命名都尽量使用了英文或英文缩写,这里写一下部分变量:

变量名作用
i、j循环变量
flag标志作用
tmp临时变量
frac分数
low、high数字范围
answer结果
sign符号
para参数
infix中缀表达式
postfix后缀表达式
point栈顶指针

函数的命名我们充分发挥了想象力。。

函数名作用
getRand获取随机数
getAndCalculate获取表达式
transEquation中缀转为后缀
countEquation计算后缀的值
ifOnly判断重复
checkAndOutput检验答案并输出正确答案
finalOut输出正误个数
gcd最大公约数
fixUp维护分母为正
getFrac生成分数
transFrac整数转化为分数
simplify分数化简
transString分数转为字符串(不判断整数)
transToString分数转为字符串(判断整数)
operator +、-、*、/分数四则运算

实现思路和遇到的困难

这里主要讲我负责的分数和栈的部分。

最初看到这个题目,觉得最难的部分就是如何处理分数。分数牵扯到了方方面面,比如:

  • 如何生成分数;
  • 如何保存分数(表达式中分数的格式);
  • 分数与整数的关系;
  • 如何计算分数;
  • 如何在栈中处理分数;

因为曾经看过c++的分数类,所以决定对分数进行单独处理,用一个独立的文件负责分数的生成、格式转换和计算。

为了能方便地分离生成表达式与计算表达式两部分,我们决定将所有数字在计算时当作分数处理(整数/1),将分子与分母分离,对所有数据都进行整型和字符串两种格式的保存。

字符串类型上,因为string能比较方便地进行字符串的组合连接,所以没有使用char[]。但是怎么把数字转换成字符串就有点麻烦了。的确c++中数字和字符串相互转换的方法很多,但是多数还是需要char[]的。我想找到一个除itoa()外的能直接通过string作转换的通用方法,以便处理小规模的数据,毕竟itoa()是平台相关的。最终找到了stringstream,真的超级方便,可以适用于string与各种数据类型的转换。不过这么方便让我不禁怀疑起其中的坑。。不过使用到现在只知道要注意多次转换需要clear(),之后还会继续学习串流的知识。

我通过随机生成两个整数,将大的作为分母,小的作为分子来生成分数。分子分母分别保存后,分数的计算也就简单了。比如加法,答案的分子就是x的分子 × y的分母 + x的分母 × y的分子,分母就是x的分母 × y的分母,最后再化简,就得到了得数。

关于如何在栈中处理分数,我是将所有分数都作加括号处理,而表达式中的括号则用中括号来代替,这样就能将分数作为一个整体来处理。

的部分,其实就是将生成的中缀表达式转换成后缀后再计算。不过这次我试用了c++的堆栈容器stack,的确让代码简洁清楚了些。计算后缀时,因为参数和得数都是分数形式的,所以用了分数类数组来作为栈。

表达式计算这部分,除了转换为后缀,也有直接用中缀计算的方法,但是个人觉得后缀的方法更加简洁通用。

除了上面说的,实际实现过程中还碰到了不少问题,特别是在写类的时候,不作不会死。。。其实简单用函数就可以了,只是我对操作符重载挺好奇的,就在这试了一下,结果意外地成功了,虽然还是碰到了很多问题。类的知识我还有好些没能理解,应该说对于类本身我就不是很理解,感觉我就像是在把类当作函数用。。

还有就是计算后缀时,用作将字符转换为数字的变量需要用double,用int计算结果会出错。最初我不知道问题出在哪,所以去翻了网上一些计算中缀表达式的程序,发现了这个差别,只是不知道为什么要用double。。

其他一些零碎的问感觉不是很有写出来的必要,如果有需要补充,会添加在下次的总结中。


代码(个人负责部分)

其他需要注释的部分会在下次添加

/*************************************************************
文件名:fraction.cpp 
作者:许郁杨 日期:2016/02/16
描述: 分数类 
主要功能包括:分数的生成、转换和四则运算 
*************************************************************/

#include"head.h"

int Fraction::greatestCommonDivisor(int x,int y) //最大公约数 
{
    if (y==0) return x;
    else return greatestCommonDivisor(y,x%y);
}
Fraction::Fraction(){ }
Fraction Fraction::getFrac(int l,int h) //生成分数 
{
    Fraction frac;
    int tmp1,tmp2;
    char tmpc[MAX];
    stringstream tmps5,tmps6;
    tmp1=getRand(l,h);
    tmp2=getRand(l,h);
    frac.numerator=Min(tmp1,tmp2);
    frac.denominator=Max(tmp1,tmp2);
    tmps5<<frac.numerator;
    tmps5>>frac.numerators;
    tmps6<<frac.denominator;
    tmps6>>frac.denominators;
    return frac;
}
Fraction Fraction::transFrac(int up,int down) //整数转换为分数 
{
    Fraction frac;
    stringstream tmps9,tmps10;
    frac.numerator=up;
    frac.denominator=down;
    tmps9<<frac.numerator;
    tmps9>>frac.numerators;
    tmps10<<frac.denominator;
    tmps10>>frac.denominators;
    return frac;
}
void Fraction::fixUp(Fraction frac) //维护分母为正 
{
    if (frac.denominator<0)
    {
        frac.denominator=-frac.denominator;
        frac.numerator=-frac.numerator;
    }
}
Fraction Fraction::simplify(Fraction frac) //分数化简 
{
    int tmp;
    char tmpc[MAX];
    stringstream tmps7,tmps8;
    fixUp(frac);
    if (frac.numerator==0) frac.denominator=1;
    else
    {
        tmp=greatestCommonDivisor(fabs(frac.numerator),fabs(frac.denominator));
        frac.numerator/=tmp;
        frac.denominator/=tmp;
    }
    tmps7<<frac.numerator;
    tmps7>>frac.numerators;
    tmps8<<frac.denominator;
    tmps8>>frac.denominators;
    return frac;
}
string Fraction::transString(Fraction frac) //分数转为字符串(不判断整数)
{
    string str;
    str="("+frac.numerators+"\\"+frac.denominators+")";
    return str;
}
string Fraction::transToString(Fraction frac) //分数转为字符串(判断整数)
{
    string str;
    if (frac.denominator==1) str=frac.numerators;
    else str="("+frac.numerators+"\\"+frac.denominators+")";
    return str;
}
const Fraction operator +(Fraction frac1,Fraction frac2) //加法 
{
    Fraction answer;
    answer.numerator=frac1.numerator*frac2.denominator+frac1.denominator*frac2.numerator;
    answer.denominator=frac1.denominator*frac2.denominator;
    return answer.simplify(answer);
}
const Fraction operator -(Fraction frac1,Fraction frac2) //减法 
{
    Fraction answer;
    answer.numerator=frac1.numerator*frac2.denominator-frac1.denominator*frac2.numerator;
    answer.denominator=frac1.denominator*frac2.denominator;
    return answer.simplify(answer);
}
const Fraction operator *(Fraction frac1,Fraction frac2) //乘法 
{
    Fraction answer;
    answer.numerator=frac1.numerator*frac2.numerator;
    answer.denominator=frac1.denominator*frac2.denominator;
    return answer.simplify(answer);
}
const Fraction operator /(Fraction frac1,Fraction frac2) //除法 
{
    Fraction answer;
    answer.numerator=frac1.numerator*frac2.denominator;
    answer.denominator=frac1.denominator*frac2.numerator;
    return answer.simplify(answer);
}
/*************************************************************
文件名:stack.cpp 
作者:许郁杨 日期:2016/02/16
描述: 栈 
主要功能包括:中缀转换为后缀、计算后缀 
*************************************************************/

#include"head.h"

stack<char> stored; //运算符栈 
void transEquation(string infix,char postfix[]) //中缀转为后缀 
{
    int i=0,j=0;
    while (infix[i]!='\0')
    {
        if ((infix[i]>='0')&&(infix[i]<='9')) //判断数字 
        {
            while ((infix[i]>='0')&&(infix[i]<='9'))
            {
                    postfix[j]=infix[i];
                    i++;
                    j++;
            }
            postfix[j]='!'; //标识单个整数 
            j++;
        }
        if (infix[i]=='(') //判断分数 
        {   
            while (infix[i]!=')') //将分数作为整体 
            {
                postfix[j]=infix[i];
                i++;
                j++;
            }
            postfix[j]=infix[i];
            i++;
            j++;
        }
        if ((infix[i]=='+')||(infix[i]=='-')) //判断'+'、'-' 
        {
            while ((!stored.empty())&&(stored.top()!='['))
            {
                postfix[j]=stored.top();
                j++;
                stored.pop();
            }
            stored.push(infix[i]);
        }
        if ((infix[i]=='*')||(infix[i]=='/')) //判断'*'、'/' 
        {
            while ((!stored.empty())&&(stored.top()!='[')&&((stored.top()=='*')||(stored.top()=='/')))
            {
                postfix[j]=stored.top();
                j++;
                stored.pop();
            }
            stored.push(infix[i]);
        }
        if (infix[i]=='[') stored.push(infix[i]); //判断'[' 
        if (infix[i]==']') //判断']' 
        {
            while (stored.top()!='[')
            {
                postfix[j]=stored.top();
                j++;
                stored.pop();
            }
            stored.pop();
        }
        i++;
    }
    while (!stored.empty()) //残余运算符 
    {
        postfix[j]=stored.top();
        j++;
        stored.pop();
    }
    postfix[j]='\0'; //终止符 
}
Fraction figure[MAX]; //数栈 
string countEquation(string infix) //计算后缀的值 
{
    int i=0,point=-1;
    char postfix[MAX];
    transEquation(infix,postfix);
    while (postfix[i]!='\0')
    {
        if ((postfix[i]>='0')&&(postfix[i]<='9')) //整数入栈 
        {
            double k=0; //int会计算出错 
            while ((postfix[i]>='0')&&(postfix[i]<='9'))
            {
                k=10*k+postfix[i]-'0';
                i++;
            }
            point++;
            figure[point]=figure[point].transFrac(k,1);
        }
        else
        if (postfix[i]=='(') //分数入栈 
        {
            double up=0,down=0; //int会计算出错 
            i++;
            while (postfix[i]!='\\')
            {
                up=10*up+postfix[i]-'0';
                i++;
            }
            i++;
            while (postfix[i]!=')')
            {
                down=10*down+postfix[i]-'0';
                i++;
            }
            point++;
            figure[point]=figure[point].transFrac(up,down);
        }
        else
        {
            point--;
            switch (postfix[i])
            {
                case '+':figure[point]=figure[point]+figure[point+1];
                         break;
                case '-':figure[point]=figure[point]-figure[point+1];
                         break;
                case '*':figure[point]=figure[point]*figure[point+1];
                         break;
                case '/':figure[point]=figure[point]/figure[point+1];
            }
        }
        i++;
    }
    return figure[point].transToString(figure[point]);
}

提交记录

因为时间关系,所以提交GitHub很多是由我来做的,实际情况可以看队友博客。如果需要其他的证据截图,会在下次博客补充。

此处输入图片的描述
此处输入图片的描述

转载于:https://www.cnblogs.com/S031602240/p/6399917.html


http://www.niftyadmin.cn/n/1499625.html

相关文章

组件化

组件化组件化回顾组件注册组件注册方式全局组件局部组件调试组件注册的过程组件的创建过程回顾首次渲染过程组件化回顾 一个Vue组件就是一个拥有预定义选项的一个Vue实例一个组件可以组成页面上一个功能完备的区域,组件可以包含脚本,样式,模板 组件注册 组件注册方式 全局组…

JVM内存设置多大合适?Xmx和Xmn如何设置?

JVM内存设置多大合适&#xff1f;Xmx和Xmn如何设置&#xff1f; 问题:新上线一个java服务&#xff0c;或者是RPC或者是WEB站点&#xff0c; 内存的设置该怎么设置呢&#xff1f;设置成多大比较合适&#xff0c;既不浪费内存&#xff0c;又不影响性能呢&#xff1f; 分析&#x…

阿里云提示Discuz uc.key泄露导致代码注入漏洞uc.php的解决方法

适用所有用UC整合 阿里云提示漏洞&#xff1a; discuz中的/api/uc.php存在代码写入漏洞,导致黑客可写入恶意代码获取uckey,.......... 漏洞名称&#xff1a;Discuz uc.key泄露导致代码注入漏洞 补丁文件&#xff1a;/api/uc.php补丁来源&#xff1a;云盾自研 解决方法&#xff…

Intellij IDEA 14中使用MyBatis-generator 自动生成MyBatis代码

一&#xff1a;项目建立好及其基本的测试好 二&#xff1a;在maven项目的pom.xml 添加mybatis-generator-maven-plugin 插件 <build><finalName>CourseDesignManage</finalName><plugins><plugin><groupId>org.mybatis.generator</grou…

redis使用watch完成秒杀抢购功能

Redis使用watch完成秒杀抢购功能&#xff1a;使用redis中两个key完成秒杀抢购功能&#xff0c;mywatchkey用于存储抢购数量和mywatchlist用户存储抢购列表。它的优点如下&#xff1a;1. 首先选用内存数据库来抢购速度极快。2. 速度快并发自然没不是问题。3. 使用悲观锁&#xf…

CSS之BFC(Block Formatting Context)

这是我的第一篇博客&#xff0c;不知道从什么开始写起&#xff0c;那就从我现在看的开始写起吧。 以前我也不知道BFC是什么&#xff0c;今天看了才知道原来以前经常接触&#xff0c;只是不知道专业名称罢了。就像闭包、继承一样&#xff0c;以前经常用到&#xff0c;只是不知道…

个人博客练手项目

最近比较闲&#xff0c;学了一些杂七杂八的技术&#xff0c;但不知道怎么用&#xff0c;想的是做一个简单的博客项目来练手&#xff0c;不知道能不能坚持下去&#xff0c;现在把项目框架搭建好了 项目技术选择 后端&#xff1a;nodeexpressmongoose前端&#xff1a;vue2vue-rou…

服务器端渲染基础

服务器端渲染基础概念什么是渲染传统的服务端渲染通过Node.js演示传统的服务器端渲染模式客户端渲染现代化的服务端渲染服务端渲染使用建议概念 随着前端技术栈和工具链的迭代成熟,前端工程化,模块化成为了当下主流技术方案,在这比技术浪潮中,涌现了诸如Anfular,React,Vue等基…