数据结构(十)栈的作用--大数的加法运算

  一、大数加法的定义

  在Java中,整数类型有四种,byte(8位)、short(16位)、int(32位)、long(64位)。

  其中,int类型为32为,也就是说最大的整数为2^31,如果超过了这个数,那么就不能再用整型变量来保存,更不用说保存两个这么大的数的和了。

  大数就是值超过整数最大上限的数,为了解决两个大数的求和问题,可以把两个加数看成是数字字符串,将这些数的相应数字存储在两个栈中,并从两个栈中弹出对应位的数字一次执行加法即可得到结果。

 

  二、大数加法的实现

  1.代码实现

    public String addOfLargeNum(String a, String b) throws Exception {
        LinkStack sum = new LinkStack();              // 大数的和
        LinkStack sA = numSplit(a);                    // 加数字符串以单个字符的形式放入栈中
        sA.stackTraverse();
        LinkStack sB = numSplit(b);                    // 被加数字符串以单个字符的形式放入栈中
        sB.stackTraverse();
        int partialSum;                                // 对应位置的两个数相加
        boolean isCarry = false;                    // 是否仅为标识
        while (!sA.isEmpty() && !sB.isEmpty()) {    // 两个栈都不为空
            partialSum = (Integer) sA.Pop() + (Integer)sB.Pop();    // 将两个栈的栈顶元素即大数的个位相加
            if (isCarry) {                // 判断低位是否有进位
                partialSum++;            // 如果有进位就加1
                isCarry = false;        // 重置进位标识
            }
            if (partialSum >= 10) {        // 如果超过了10就需要进位
                partialSum -= 10;        // 取个位数字
                sum.Push(partialSum);    // 将得到的加和入大数的和栈
                isCarry = true;            // 将进位标志位置为true
            } else {
                sum.Push(partialSum);    // 不需要进位时直接放入栈中
            }
        }
        LinkStack temp = !sA.isEmpty()? sA : sB;    // 如果有一个加数比另一个加数短,则取长的那个加数加完剩下的栈
        while (!temp.isEmpty()) {                    
            if (isCarry) {                            // 最后一次执行加法运算中需要进位
                int t = (Integer)temp.Pop();        // 取出没有参加加法的位
                t++;                                // 加上进位位1
                if (t >= 10) {                        // 如果超过10,就需要进位
                    t -= 10;
                    sum.Push(t);                    // 这里没有改变进位标识isCarry,下一次还是true
                } else {
                    sum.Push(t);                    // 不需要进位时直接入和栈
                    isCarry = false;                
                }
            } else {
                sum.Push(temp.Pop());
            }
        }
        if (isCarry) {        // 最高一位入栈后仍然需要进位的情况
            sum.Push(1);    // 再最高位的前一位入栈
        }
        String str = new String();
        while (!sum.isEmpty()) {    // 将栈中的数按正常顺序转化为字符串输出
            str = str.concat(sum.Pop().toString());
        }
        return str;
    }
    
    // 将字符串以单个字符的形式放入栈中,并去除字符串中的空格,返回以单个字符为元素的栈
    private LinkStack numSplit(String str) throws Exception {
        LinkStack s = new LinkStack();
        for (int i = 0; i < str.length(); i++) {        
            char c = str.charAt(i);                        
            if (c == ' ') {                                        // 去除空格
                continue;    
            } else if ('0' <= c && c <= '9') {                    // 判断是不是0到9之间的数
                s.Push(Integer.valueOf(String.valueOf(c)));        // 如果是,就将数字入栈
            } else {
                throw new Exception("输入了非法数字型字符");
            }
        }
        return s;
    }

  2.测试和输出

    public static void main(String[] args) throws Exception {
        AdditionOfLargeNumbers add = new AdditionOfLargeNumbers();
        String largeNum1 = "18 452 453 389 943 209 752 345 473";
        String largeNum2 = "8 123 542 678 432 986 899 334";
        System.out.println("两个大数相加得到的和为: " + add.addOfLargeNum(largeNum1, largeNum2));
        System.out.print("\n");
        System.out.println("两个大数相加得到的和为: " + add.addOfLargeNum("784", "8 465"));
    }

输出:
此时,链栈中的元素为: 37454325790234998335425481
此时,链栈中的元素为: 4339986892348762453218
两个大数相加得到的和为: 18460576932621642739244807

此时,链栈中的元素为: 487
此时,链栈中的元素为: 5648
两个大数相加得到的和为: 9249

  3.分析代码执行过程

大数加法算法中主要是isCarry标志位的切换:以“784” + “8 465”为例:
首先,将两个字符取出空格并压入两个栈中,即sA=(栈顶)487, sB=(栈顶)5648
然后4出栈,5出栈,4+5=9,isCarry为false,9入栈sum,
然后8出栈,6出栈,8+6=14,isCarry为true,14-10=4入栈sum,
然后7出栈,4出栈,7+4+1=12,isCarry为true,12-10=2入栈sum,
此时sA为空,temp=sB=8,8出栈,8+1=9,isCarry为false,9入栈sum,
最后将栈sum按顺序输出为:924
posted @ 2018-06-15 16:14  BigJunOba  阅读(740)  评论(0编辑  收藏  举报