整数是有上限的,所谓大数,是指超过整数最大上限的数,例如18452545389943209751345473,
它是无法用整数变量来保存的。为解决两个大数求和问题,可以把两个加数看成是数字字符串。
由于最先写的高位反而最后运算,满足栈先进后出的特性,因此选择用栈来解决这个问题。
操作步骤如下:
1)将两个加数的相应位从高位到低位依次压入栈sA和sB中。
2)若两个加数栈都非空,则依次从栈中弹出栈顶数字相加,和存入变量partialSum中;
若和有进位,则将和的个位数压入结果栈sum中,并将进位数加到下一位数字相加的和中;
若没有进位,则直接将和压入结果栈sum中。
3)若某个加数堆栈为空,则将非空加数的栈顶数字依次弹出与进位相加,和的个位数压入结果栈sum中,
直到该栈为空为止,若最高位有进位,则最后将1压入sum中。
4)若两个加数栈都为空,则栈sum中保存的就是计算结果。此时栈顶存储的是最高位数字。
代码如下,用到了之前实现的链栈,代码中有详细注释
package com.stack;
public class AdditionOfLargeNumbers {
public static LinkStack numSplit(String str) throws Exception {
// 将字符串以单个字符的形式压入栈,并且去除其中的空格,返回栈
LinkStack s = new LinkStack();
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);// 指定索引处的char值
if (c == ' ') {
continue;// 如果是空格,则跳过
} else if ('0' <= c && c <= '9') {
s.push(Integer.valueOf(String.valueOf(c)));
} else {
throw new Exception("错误:输入了非数字类型");
}
}
return s;
}
public static String add(String oa, String ob) throws Exception {
LinkStack sum = new LinkStack();
LinkStack sA = numSplit(oa);
LinkStack sB = numSplit(ob);
int partialSum = 0;// 存储单位数字相加的结果
boolean isCarry = false;// 是否进位
while (!sA.isEmpty() && !sB.isEmpty()) {// 当两个栈里都还有数字
partialSum = (Integer) sA.pop() + (Integer) sB.pop();
if (isCarry) {
// 因为一开始来肯定没有上一位的进位,因此先判断此项,有进位就加
partialSum++;// 如果之前有进位,则加到此位上
isCarry = false;// 重置进位标志
}
if (partialSum >= 10) {//能够进位
partialSum -= 10;
sum.push(partialSum);
isCarry = true;//标记进位
} else {//位和不需要进位
sum.push(partialSum);
}
}
LinkStack temp=sA.isEmpty()?sB:sA;//如果sA为空则加sB,否则sB为空加sA
while(!temp.isEmpty()){
if(isCarry){//最后一次执行加法运算需要进位
int t=(Integer)temp.pop();
++t;//进位加到此位上
if(t>=10){
t-=10;
sum.push(t);
}
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;
}
public static void main(String[] args) throws Exception {
System.out.println(add("18 452 543 389 943 209 752 345 473",
"8 123 542 678 432 986 899 334"));
}
}