zoukankan      html  css  js  c++  java
  • Linux C/C++ 编程练手 --- 大数相加和大数相乘

    最近写了一个大数相乘和相加的程序,结果看起来是对的。不过期间的效率可能不是最好的,有些地方也是临时为了解决问题而直接写出来的。

    可以大概说一下相乘和相加的解决思路(当然,大数操作基本就是两个字符串的操作了):

    一、思路:

    在操作大数前,一定会有一些异常判断,比如输入的字符串是否合法(是否是纯数字?是否为空?等等),然后才是具体的操作实现:

    1、大数相加(大体思路:将大数相加问题,转换成十以内的两数相加):

    ①申请合适的空间,一般可以认定,两个数字相加时,长度至多是最长的数的长度或最长的数的长度加1;

    ②从个位(字符串中就是从最后一位)开始,进行逐位相加;

    ③每位相加后,立即判断是否有进位,再将本次计算的个位数字记录到result字符串中;

    ④当短字符串过完后,按照同样的方式,过完长字符串的剩余数字;

    ⑤长字符串过完后,判断是否存在进位,如果有,则最后再赋值到result字符串中,如果没有,则最后将0(也就是结束符)赋值到result字符串中;

    ⑥由于操作的result字符串是倒置操作的,最后再把字符串逆置,返回即为两数相加结果;

    2、大数相乘(大体思路:将大数相乘问题,转换成十以内的两数相乘):

    ①按照一般的两数相乘的思路,运算过程中,会产生一个二维数组样式的中间结果(准确点是一个字符串数组),数组的行数是第二个数字的个数;

    ②每次得出这个字符串数组的一行的结果,具体为:

    a、针对这个字符串数组,每次运算前,申请合适的空间,一般可以认定,一个数和一个十以内的数字相乘时,长度至多是该数的长度或该数长度加1;但是还有一点需要考虑到,从十位开始,数字相乘后,默认是在最后加0的,规律为十位对应1个0,百位对应2个0,以此类推。因此需要申请的空间除了该数的长度加1外,还需要加上本次操作需要额外增加的0的个数;

    b、在数字真正相乘前,需要将对应的0进行补齐(即个位数相乘时增加0个0,十位数相乘时增加1个0 ... ... )

    c、每次取出第二个数的一个数字,取出顺序为倒序(从个位开始),然后与第一个数字进行逐位相乘;

    d、相乘结果判断进位,并且保存,此次乘出来的结果保留个位数字,放入到本行的字符串结果中;

    e、过完第一个数字的长度后,判断是否有进位,有的话则直接将进位赋值到本行字符串结果中,没有的话则将0赋值到本行字符串结果中;

    f、然后循环进行,直到将第二个数字过完后,就会产出一个二维数组(或称之为字符串数组);

    ③最后把这个字符串数组的每一行相加(用到上面的大数相加函数来做),就是最终的相乘结果;


    二、代码:

    1、大数相加:

    char *BigNumSum(char *bignum1, char *bignum2)
    {
            char *result, *big, *small;
            int bignum1_length = strlen(bignum1);
            int bignum2_length = strlen(bignum2);
            int bigger, smaller;
    
            if(bignum1_length >= bignum2_length)
            {
                    bigger = bignum1_length;
                    smaller = bignum2_length;
                    big = bignum1;
                    small = bignum2;
            }
            else
            {
                    bigger = bignum2_length;
                    smaller = bignum1_length;
                    big = bignum2;
                    small = bignum1;
            }
    
            int tmp, tmp_gewei, tmp_jinwei = 0, num = 0;
            result = (char *)malloc(sizeof(char) * (bigger + 1));
            for(int i = smaller - 1, j = bigger - 1; i >= 0 && j >= 0; i--, j--)
            {
                    char *tmp_big = ctocs(big[j]);
                    char *tmp_small = ctocs(small[i]);
                    tmp = atoi(tmp_big) + atoi(tmp_small) + tmp_jinwei;
                    tmp_gewei = tmp % 10;
                    tmp_jinwei = tmp / 10;
                    result[num++] = tmp_gewei + ASICNUM;
            }
            for(int i = bigger - smaller - 1; i >= 0; i--)
            {
                    char *tmp_big = ctocs(big[i]);
                    tmp = atoi(tmp_big) + tmp_jinwei;
                    tmp_gewei = tmp % 10;
                    tmp_jinwei = tmp / 10;
                    result[num++] = tmp_gewei + ASICNUM;
            }
            if(tmp_jinwei > 0)
            {
                    result[num] = tmp_jinwei + ASICNUM;
            }
            else
            {
                    result[num] = 0;
            }
            recover(result);
            return result;
    }

    2、大数相乘:

    char *BigNumMultip(char *bignum1, char *bignum2)
    {
            char *result;
            int bignum1_length = strlen(bignum1);
            int bignum2_length = strlen(bignum2);
    
            char *tmp[bignum2_length];
            int i;
            for(i = bignum2_length - 1; i >= 0; i--)
            {
                    int t;
                    int j;
                    tmp[i] = (char *)malloc(sizeof(char) * (bignum1_length + 1 + (bignum2_length -1 - i)));
                    for(t = 0; t < bignum2_length -1 - i; t++)
                            tmp[i][t] = 0 + ASICNUM;
                    int tmp_jinwei = 0;
                    for(j = bignum1_length - 1; j >= 0; j--)
                    {
                            char *tmp_bignum1 = ctocs(bignum1[j]);
                            char *tmp_bignum2 = ctocs(bignum2[i]);
                            int tmp_multip = atoi(tmp_bignum1) * atoi(tmp_bignum2) + tmp_jinwei;
                            int tmp_gewei = tmp_multip % 10;
                            tmp_jinwei = tmp_multip / 10;
                            tmp[i][t++] = tmp_gewei + ASICNUM;
                    }
                    if(tmp_jinwei > 0)
                    {
                            tmp[i][t] = tmp_jinwei + ASICNUM;
                    }
                    else
                    {
                            tmp[i][t] = 0;
                    }
                    recover(tmp[i]);
    //              puts(tmp[i]);
            }
            result = (char *)malloc(sizeof(char) * (strlen(tmp[i+1]) + 1));
            memset(result, '0', strlen(result));
            for(int i = 0; i < bignum2_length; i++)
            {
                    result = BigNumSum(tmp[i], result);
            }
            
            return result;
    }

    3、其他:

    ①字符串逆置:

    void recover(char *string)
    {
            int length = strlen(string);
            int tmp;
            for(int i = 0; i < length / 2; i++)
            {
                    tmp = string[i];
                    string[i] = string[length - i - 1];
                    string[length - i - 1] = tmp;
            }
    }

    ②判断是否是数字字符串:

    bool isDigital(char *string)
    {
            bool ret = true;
            int length = strlen(string);
    
            for(int i = 0; i < length; i++)
            {
                    if(string[i] < '0' || string[i] > '9')
                    {
                            ret = false;
                            break;
                    }               
            }
            return ret;
    }

    ③字符转换为字符串:

    char *ctocs(char ch)
    {
            char *a;
            a = (char *)malloc(sizeof(char) * 2);
            a[0] = ch;
            a[1] = 0;
    
            return a;
    }

    ④main函数调用:

    int main(int argc, char **argv)
    {
            if(3 != argc)
            {
                    printf("error
    ");
                    return 1;
            }
            char *bignum1 = argv[1];
            char *bignum2 = argv[2];
    
            bool ret1 = isDigital(bignum1);
            bool ret2 = isDigital(bignum2);
    
            if(false == ret1 || false == ret2)
            {
                    printf("input not number
    ");
                    return 2;
            }
            char *multip_result = BigNumMultip(bignum1, bignum2);
            char *sum_result = BigNumSum(bignum1, bignum2);
    
            printf("数字 1:%s
    数字 2:%s
    两数积:%s
    两数和:%s
    ", bignum1, bignum2, multip_result, sum_result);
            return 0;
    }


    这段代码也就是按照一个最基本的思路进行简单的实现,基本如上,没有太多注释,目前可以预见到的问题就是:①执行效率、②内存消耗;后面有空会再进行优化的~

    目前测试了一些数字,是可以正确返回的(当然,太大的数字也就是验证的后面或前面的几位的数字)。如果大家有发现不对有有问题的地方,求指点~

  • 相关阅读:
    验证LeetCode Surrounded Regions 包围区域的DFS方法
    Qt Package Project 打包发布程序
    [LeetCode] Missing Number 丢失的数字
    [CareerCup] 6.4 Blue Eyes People on Island 岛上的蓝眼人
    [CareerCup] 6.3 Water Jug 水罐问题
    [CareerCup] 6.2 Dominos on Chess Board 棋盘上的多米诺
    [CareerCup] 6.1 Find Heavy Bottle 寻找重瓶子
    [CareerCup] 5.8 Draw Horizonatal Line 画横线
    Print or Cout an Unsigned Char Variable 打印无符号字符
    Kinect 学习链接
  • 原文地址:https://www.cnblogs.com/james1207/p/3358037.html
Copyright © 2011-2022 走看看