WHCSRL 技术网

20. 计算器PLUS


1 问题描述

高老师的学术科研开展的如火如荼,但最近有件事让他很烦恼,在做学术研究过程中,经常需要对很大很大的数据进行计算,而现有的计算器没办法满足这种计算需求,所以现在想请大家帮忙实现一个计算器PLUS版。

为了减少大家的工作量,高老师已经将函数的输入输出接口定义完成,你只需编写计算器PLUS的核心部分。

例如 plus() , minus() 和 multiply() 函数,有三个char * 类型的参数 a、b 和 c,a 和 b 分别是参与运算的两个整数,c 用来存放运算结果。所有数字以字符串的形式保存。你的计算结果(在 c 中保存)中不应包含任何前导零。

* 注意,你只需提交编写的三个函数即可。

所有的测试点中的整数,包括结果整数的十进制位数均不超过 1000,均保证其包含的所有整数非负。但不保证结果非负。

输入的数字可能存在前导0


预设代码

前置代码

/* PRESET CODE BEGIN - NEVER TOUCH CODE BELOW */

#include <stdio.h>
#include <string.h>

void plus(const char * a, const char * b, char * c);
void minus(const char * a, const char * b, char * c);
void multiply(const char * a, const char * b, char * c);

int main()
{
    static char a[100005];
    static char b[100005];
    static char c[200005];
    static char s[2];
    
    while (scanf("%%s %%s %%s", a, s, b) == 3) {
        if (s[0] == '+') {
            plus(a, b, c);
        } else if (s[0] == '-') {
            minus(a, b, c);
        } else if (s[0] == '*') {
            multiply(a, b, c);
        }
        printf("%%s
", c);
    }

    return 0;
}

/* PRESET CODE END - NEVER TOUCH CODE ABOVE */
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

 测试输入 期待的输出 时间限制 内存限制 额外进程
测试用例 1以文本方式显示
  1. 1 + 2↵
  2. 3 - 2↵
  3. 1 * 2↵
以文本方式显示
  1. 3↵
  2. 1↵
  3. 2↵
1秒64M0

2 解题

<1>第一次尝试

  • 刚开始没有意识到这个题的考点,还以为是要复习一下C语言的知识点,字符串和整型数字的转换,于是我开始了

  • 代码就不放了,总之就是算是偷懒的做法
    在这里插入图片描述
    代码主要是在提取,提取出来以后直接相乘得到结果,然后再把结果存进去
    在这里插入图片描述

  • 不过也借这个机会复习了一下怎么转换字符串和int整型这两种类型了,整理了一下,记录在这了
    https://blog.csdn.net/qq_41680771/article/details/121058779


<2> 最终AC版

  • 其实算法很简单(没有算法好像),主要就是不断调试来修改代码符合题意

  • 题目中说位数不超过1000,我们平时说的一亿才11位,所以提取出来进行运算的操作肯定是不行的了

  • 输入可能会有前缀0,注意进行处理避免没必要的运算,另外输出是不需要前缀的

  • 加法:每一位取出来相加,对应的结果报存在整型数组tmp[]里面,注意是从后往前存的,然后遍历一遍,根据10进制特点和规律进行调整,相加的话可能会使得位数增加

  • 减法:结果的正负处理方式不一样,分开处理,最后的结果如果是负数的话,需要在c里面加上“-”号

  • 乘法:我是对于b的每一位,用a的每一位去乘它,对应结果保存在tmp的相应位置
    在这里插入图片描述

  • 好吧,其实就是竖式运算~~~

    得到的结果累加,最后再处理

  • 代码

#include <stdio.h>  
#include <string.h>  
  
void plus(const char * a, const char * b, char * c);  
void minus(const char * a, const char * b, char * c);  
void multiply(const char * a, const char * b, char * c);  
  
int main()  
{  
    static char a[100005];  
    static char b[100005];  
    static char c[200005];  
    static char s[2];  
    //freopen("file out.txt","r",stdin);  
    while (scanf("%%s %%s %%s", a, s, b) == 3) {  
        if (s[0] == '+') {  
            plus(a, b, c);  
        } else if (s[0] == '-') {  
            minus(a, b, c);  
        } else if (s[0] == '*') {  
            multiply(a, b, c);  
        }  
        printf("%%s
", c);  
    }  
  
    return 0;  
}  

void plus(const char * a, const char * b, char * c){
    int lena,lenb,lentmp;
    int notzeroA,notzeroB;
    int tmp[20005];
    int i=0;
    int flag=0;

    lena = strlen(a);
    lenb=strlen(b);
    
    while(a[i]=='0')    //处理前缀0
        i++;
    notzeroA=i;         //第一个不是0的位置
    i=0;
    while(b[i]=='0')
        i++;
    notzeroB=i;
    // for(i=0;(lena--)>0||(lenb--)>0;i++){ //这个会导致后面一个语句不运行,||类型,前面已经是真的了
    for(i=0;lena>notzeroA||lenb>notzeroB;i++){
        lena--; lenb--;
        if(lena<notzeroA){  //a完了
            tmp[i]=b[lenb]-'0';
        }
        else if(lenb<notzeroB){ //b完了
            tmp[i]=a[lena]-'0';
        }
        else
            tmp[i]=(a[lena]-'0')+(b[lenb]-'0');        
    }
    lentmp=i;
    for(i=0;i<lentmp;i++){
        if(flag){
            tmp[i]+=1;
            flag=0;
        }
        if(tmp[i]>9){
            flag=1; //需要进1的标志
            tmp[i]%%=10;
        }        
    }
    if(flag)    //总和大于当前位数,需要增加
        tmp[lentmp++]=1;
    while(tmp[lentmp-1]==0)
        lentmp--;     
    for(i=0;i<lentmp;i++){
        c[i]=tmp[lentmp-i-1]+'0';
    }
    c[i]='';  //记得增加结束符

}  
void minus(const char * a, const char * b, char * c){
    int lena,lenb,lentmp;
    int tmp[20005];
    int i=0;
    int flag=0;
    int positiveflag=0;

    lena = strlen(a);
    lenb=strlen(b);
    
    
    for(i=0;lena>0||lenb>0;i++){
        lena--; lenb--;
        if(lena<0){
            tmp[i]=0-(b[lenb]-'0');
        }
        else if(lenb<0){
            tmp[i]=a[lena]-'0';
        }
        else
            tmp[i]=(a[lena]-'0')-(b[lenb]-'0');        
    }
    lentmp=i;
    
    while(i--){     //只要第一个不为0的数大于0,那么结果就是正数,注意tmp的逆序存储
        if(tmp[i]!=0){
            if(tmp[i]>0){
                positiveflag=1;
                break;
            }
            else if(tmp[i]<0){
                break;
            }                
        }
    }
    

    if(positiveflag){   //正数处理
        for(i=0;i<lentmp;i++){
            if(flag){
                tmp[i]-=1;
                if(tmp[i]<0){
                    tmp[i]+=10;
                }
                else
                    flag=0;
            }
            else{
                if(tmp[i]<0){
                    tmp[i]+=10;
                    flag=1;
                }
            }
        }
        flag=0;
    }
    else{
        for(i=0;i<lentmp;i++){
            if(flag){            
                tmp[i]+=1;
                if(tmp[i]>0){
                    tmp[i]=tmp[i]*(-1)+10;
                }
                else if(tmp[i]<0){
                    tmp[i]*=(-1);
                    flag=0;
                }
                else{
                    flag=0;
                }       
            }
            else{
                if(tmp[i]>0){
                    tmp[i]=tmp[i]*(-1)+10;
                    flag=1;
                }
                if(tmp[i]<=0){
                    tmp[i]*=(-1);                
                } 
            }        
                
        }
    }  

    i=lentmp;   //处理前缀0,输出不需要前缀
    while(i--){
        if(tmp[i])
            break;
    }
    lentmp=++i;

    if(positiveflag){
        for(i=0;lentmp--;i++){        
            c[i]=tmp[lentmp]+'0';
        }
    }
    
    else{
        if(tmp[lentmp-1]!=0){   //负数需要添加-号
            c[0]='-';
            for(i=1;lentmp--;i++){        
                c[i]=tmp[lentmp]+'0';
            }
        }
        else{
            i=0;
            c[i++]='0';
        }
        
        
    }
    
    c[i]='';
}


void multiply(const char * a, const char * b, char * c){
    int lena,lenb,lentmp;
    int notzeroA,notzeroB;
    int tmp[20005]={0};
    int i=0,j=0,k=0;
    int flag=0;
    lena=strlen(a);
    lenb=strlen(b);
    
    while(a[i]=='0')
        i++;
    notzeroA = i;
    while(b[j]=='0')
        j++;
    notzeroB = j;
    if(!lena||!lenb||i==lena||j==lenb){     //如果有是0的项,那么完全没必要再操作了
        c[0]='0';
        c[1]='';
        return;
    }

    i=lenb;
    while(--i>=notzeroB){
        j=lenb-i-1;     //tmp下标每次的开始是在增加的
        k=lena;
        if(b[i]=='0')
            continue;
        while(--k>=notzeroA){
            tmp[j++]+=(a[k]-'0')*(b[i]-'0');
        }
    }

    for(i=0;i<j;i++){
        if(flag){
            tmp[i]+=flag;
            flag=0;
            if(tmp[i]>9){
                while(tmp[i]>9){
                    flag++;
                    tmp[i]-=10;
                }
            }
            else
                flag=0;
        }
        else{
            while(tmp[i]>9){
                flag++;
                tmp[i]-=10;
            }
        }
    }
    while(flag){    //tmp里面进行正确格式处理以后可能会位数增加
        tmp[i]+=flag;
        flag=0;
        while(tmp[i++]>9){
            flag++;
            tmp[i]-=10;
        }
    }
    lentmp=i;
    for(i=0;i<lentmp;i++){
        c[i]=tmp[lentmp-i-1]+'0';        
    }
    c[i]='';
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260

3 小结

  • while 或者for if这个射击条件判断的语句要注意编译器不一定会判断所有给出的条件,比如**&&**类型,如果第一个就是false的话,后面就不会判断了
for(i=0;(lena--)>0||(lenb--)>0;i++)
  • 1

比如这个语句如果前面就是TRUE的话,后面len–就不会运行,容易导致程序出错

推荐阅读