zoukankan      html  css  js  c++  java
  • 求助:一本通网站1356(己基本解决)

    一本通网站1356

    我写了以下代码:

    //1356:计算(calc)
    /*基本思路:后面优先级高,前面内容入栈,否则先算前面内容*/ 
    #include<iostream>
    #include<cstdio> 
    #include<cstring> 
    using namespace std;
    int const N=2e6+2;
    int stack1[N*2],cnt,x,y,x0,tp1,tp2;
    char stack2[N],ch,ch0; 
    string s;
    
    //计算运算优先组,后面优先级高就前面内容入栈,后面优先级小于等于前面优先组就先算栈内内容 
    int level(char p)
    {
        if(p=='+'||p=='-')return 1;
        if(p=='*'||p=='/')return 2;
        if(p=='^')return 3;    
        return 0;
    }
    int cf(int x,int y)//一个简单快速幂求x^y 
    {
        if(y==0)return 1;
        if(y==1)return x;
        int t=cf(x,y/2);
        t*=t;
        if(y%2)t*=x;
        return t;
    }
    //完成一次基本计算 
    void calc()
    {
        int x,y;//定义两个操作数 
        char ys;//定义一个运算符 
        ys=stack2[tp2--];
        y=stack1[tp1--];
        x=stack1[tp1];//运算一次取出两个数,并把计算结果存回,故此处没减栈顶指针 
        switch(ys)
        {
            case '+':stack1[tp1]=x+y;break;
            case '-':stack1[tp1]=x-y;break;
            case '*':stack1[tp1]=x*y;break;
            case '/':stack1[tp1]=x/y;break;
            default:stack1[tp1]=cf(x,y);//也可以直接用库函数pow(x,y) 
        }
    }
    int main(){    
        s[++cnt]='(';
        while((ch=getchar())&&ch!=13&&ch!=10)s[++cnt]=ch;
        s[++cnt]=')';
        for(int i=1;i<=cnt;i++)
        {
            ch=s[i];//ch可能为(、)、数字(包括负号)、和运算符 
            if(ch=='(')stack2[++tp2]='(';
            //遇到)就计算到(为止。遇到(之前,栈内所存运算符应该逐级上升,故需反向运算
            //如1+2*3^4
            else if(ch==')')
            {
                while(stack2[tp2]!='(')calc();
                tp2--;//让(出栈 
            }
            else if(ch>='0'&&ch<='9'||ch=='-'&&s[i-1]=='(') 
            //读到的是数字,把连续的数字变成数值 ,如果是'-'先判断前面是不是(,是则说明是负号不是减号 
            {
                if(ch=='-')x0=0,y=-1;//y代表数值的符号 
                else x0=ch-'0',y=1;
                ch0=s[++i];
                while(ch0>='0'&&ch0<='9')x0=x0*10+ch0-'0',ch0=s[++i];
                i--;
                x0*=y;
                stack1[++tp1]=x0;
            }
            else  //ch为运算符 
            {
                while(level(ch)<=level(stack2[tp2]))calc();
                //当前运算符不超过栈顶运算,先算栈顶运算 
                //此处未判断运算符栈是否为空是因为栈底是一个(,运算级最低,不可能超过当前运算等级    
                stack2[++tp2]=ch;//直到当前运算符高于栈顶运算符再把运算符存栈 
            }
        }
        cout<<stack1[tp1]<<endl;
        return 0;
    }

    有两个问题:1、在windows版DEV下运行结果如下

    而且,在出现答案258后至少会等待3秒以上程序才会结束。(多次测试都是)

    2、提交到网站后答案错误4个,运行错误一个。

    然而,就这同一个思路改成直接用stl中的stack,得到如下代码:

    //1356:计算(calc)
    /*基本思路:后面优先级高,前面内容入栈,否则先算前面内容*/ 
    #include<iostream>
    #include<stack>
    #include<cmath>
    #include<cstring> 
    using namespace std;
    int const N=1e5+1;
    int x,y;
    char ch,ch0; 
    string s;
    stack<int>s1;
    stack<char>s2;
    //计算运算优先组,后面优先级高就前面内容入栈,后面优先级小于等于前面优先组就先算栈内内容 
    int level(char p)
    {
        if(p=='+'||p=='-')return 1;
        if(p=='*'||p=='/')return 2;
        if(p=='^')return 3;    
        return 0;
    }
    
    //完成一次基本计算 
    void calc()
    {
        int m,n;
        char z;
        n=s1.top();
        s1.pop();
        m=s1.top();
        s1.pop();
        z=s2.top();
        s2.pop();
        switch(z)
        {
            case '+':s1.push(m+n);break;
            case '-':s1.push(m-n);break;
            case '*':s1.push(m*n);break;
            case '/':s1.push(m/n);break;
            default:s1.push(pow(m,n));
        }
        return;
    }
    int main(){    
        cin>>s;
        s='('+s+')';
        int i=0;
        ch='(';
        do
        {
            if(ch=='(')
            {
                s2.push('(');
            }
            
            //遇到)就计算到(为止。遇到(之前,栈内所存运算符应该逐级上升,故需反向运算
            //如1+2*3^4 
            else if(ch==')')
            {
                while(s2.top()!='(')calc();
                s2.pop();//弹出( 
            }
            else if(ch>='0'&&ch<='9'||ch=='-'&&s[i-1]=='(') 
            //读到的是数字,把连续的数字变成数值 ,如果是'-'先判断前面是不是(,是则说明是负号不是减号 
            {
                if(ch=='-')x=0,y=-1;//是负号则符号设为-1,初始值为0 
                else x=ch-'0',y=1;//默认符号为正
                ch0=s[++i];
                while(ch0>='0'&&ch0<='9')x=x*10+ch0-'0',ch0=s[++i];
                i--;
                x*=y;
                s1.push(x);
            }
            else  //ch为运算符 
            {
                while(level(ch)<=level(s2.top()))//当前运算符不超过栈顶运算,先算栈顶运算 
                {
                    calc();
                }
                s2.push(ch);//直到当前运算符高于栈顶运算符再把运算符存栈 
            }
        }while(ch=s[++i]);
        cout<<s1.top()<<endl;
        return 0;
    }

    便没有任何问题,提交后也全正确,万能的网络朋友们,请帮我看看第一个代码错在哪了?

       错因分析:对于一个string,虽然它跟char[]类似,但也不完全相同。它有固定结尾(''),是一个字符串结束的标记。虽然我们能像char[]一样一个一个地改变每一个字符的值,但,修改后的字符串并没有被系统认可。比如string s="a",这个字符串只有一个字符,存储在内存中其实是两个位置:s[0]='a',s[1]=''。字符串长度可用s.size()获得,当然这个值是1(‘'结束标记不纳入计数之列),如果我们人为修改s[1]='b',尽管你可以再加上一句:s[2]='',(感觉像是做错后的掩饰),但此时测试s.size()=1,这就说明我们修改字符方式加入的'b'并没有被字符串接受。此时如果想输出字符串,比如:cout<<s;结果也是a,没有b。再做一个测试:string s="a"; s[1]='b'; s[2]='c'; s[3]='d';此时,若cout<<s;可得到a。如果输出s[1]、s[2]、s[3]都可以得到相应的字符。若再加上一句: s+='e';然后cout<<s;显示结果会是如何?答案是ae。如果你继续显示s[1]、s[2]、s[3],那会是''。

      或许可以换个角度理解:string s;定义了,再赋值,或定义时就赋值,一旦赋值完成,那么与s等效的字符数组就确定了,数组的最大下标也就确定了(s.size()就代表字符串的长度,也可以说是字符数组不越界能访问的最大下标),如前文所说s="a",那s[2]实质上已经发生下标越界了,内存数据将会混乱,在本机还能运行,可能由于开发系统的保护抑或这个混乱尚未造成可见的错误,但在真实测试数据(数据量远比样例大得多)到来,又离开了IDE的保护,错误就显现出来了。这或许可以这么说:你的错误操作未必会得出错误结果。

      如果想增加一个字符'b’并被系统认同,当然也很简单:s+='b';,这一个操作的背后,除了在后面加了一个字符外,还实时地修改了s.size(),这个操作是配套的,也就是说同步修改了数组的边界,那就不会发生下标越界问题了。还有一事大家需要明白:s.size()是不可人为手动修改的。比如s.size()=3;这是错误的。显然嘛,你看size后面有一个括号,说明它是一个函数返回值,没有输入功能啊。所以,手动修改s[3]='b'这样的操作没办法同步边界,越界和错误是必须的。

       要想纠正这个错误那就简单了,方法也很多,本文就不讨论了。(参看第二版本)(写第一版本输入本想试下不同的输入方法的,没想搞出这么大一乌龙,收不到场了。)

      谢谢之江学院石老师的不断指点!!!

  • 相关阅读:
    R-FCN、SSD、YOLO2、faster-rcnn和labelImg实验笔记
    yolov3的anchor机制与损失函数详解
    CV资料推荐
    测试用例设计方法总结
    测试需求分析
    bug生命周期
    linux命令一
    linux 命令二
    linux 命令三
    mysql数据库和禅道安装
  • 原文地址:https://www.cnblogs.com/wendcn/p/12599909.html
Copyright © 2011-2022 走看看