如何實現大整數相加?


我們平時實現兩個整數相加,直接用兩個int類型的整數相加即可。如果整數再大一點,那么就可以將整數聲明為long類型。如果整數是數十位的,甚至是上百位的,連long類型也裝不下呢?讓我們來先回顧一下我們上小學時是如何計算兩個較大的整數想加的。小學時,要計算兩個較大整數相加,就要進行列豎式計算,將兩個整數先右對齊,再從個位開始,到十位,到百位......依次進行加法運算。那么我們為什么要列出豎式運算呢?因為我們人腦無法將兩個很大的數一步到位直接計算出結果,必須拆解成一位一位的運算。同樣,程序不可能通過一條指令就計算出兩個大整數的和,也必須一位一位的運算。但是大整數既然超過了long類型的范圍,那么計算機如何來存儲大整數呢?於是數組就派上用場了。我們可以用數組來存儲大整數的每一位。

我以426709752318 + 95481253129為例,來看看計算機進行兩個大整數相加的具體操作步驟:

第一步:由於我們都習慣從左往右地訪問數組,因此把整數倒序存儲,整數的個位存於數組0下標位置,最高位存於數組長度減1下標位置處。

第二步:創建結果數組,該數組的長度應為較大整數的位數加1。

第三步:遍歷兩個整數的數組,左對齊從左到右按照對應下標將元素相加。

例子中,首先相加的是數組A的第一個元素8和數組B的第一個元素9,得出結果7,進位1。把7填充到Result數組的對應下標,進位的1填充至下一位置:

第二組相加的是數組A的第二個元素1和數組B的第二個元素2,得出結果3,再加上剛才的進位1,結果是4,將4填充至Result數組的對應下標處:

第三組相加的是數組A的第三個元素3和數組B的第三個元素1,得出結果4,將4填充至Result數組的對應下標處:

第四組相加的是數組A的第四個元素2和數組B的第四個元素3,得出結果5,將5填充至Result數組的對應下標處:

以此類推......一直把兩個數組的所有元素都相加完畢:

第四步:把Result數組的全部元素再次逆序,去掉首位,即可得到最終結果:

代碼如下:

/**
 * 大整數求和
 * @param bigNumberA 大整數A
 * @param bigNumberB 大整數B
 */

 public static String bigNumberSum(String bigNumberA, String bigNumberB) {
     // 1.把兩個大整數用數組逆序存儲,數組長度等於較大整數位數+1
     int maxLength = bigNumberA.length() > bigNumberB.length() ? bigNumberA.length() : bigNumberB.length();
     int[] arrayA = new int[maxLength + 1];
     int[] arrayB = new int[maxLength + 1];
     for(int i = 0; i < bigNumberA.length(); i++)
         arrayA[i] = bigNumberA.charAt(bigNumberA.length() - 1 - i) - '0';
    
     for(int i = 0; i < bigNumberB.length(); i++)
         arrayB[i] = bigNumberB.charAt(bigNumberB.length() - 1 - i) - '0';

    // 2.構建result數組,數組長度等於較大整數位數 + 1
    int[] result = new int[maxLength + 1];
    // 3.遍歷數組,按位相加
    for(int i = 0; i < result.length; i++) {
        int temp = result[i];
        temp += arrayA[i] + arrayB[i];
        // 判斷是否進位
        if(temp >= 10) {
            temp = temp - 10;
            result[i + 1] = 1;
        }
        result[i] = temp;
    }

    // 4.把result數組再次逆序並轉成String
    StringBuilder sb = new StringBuilder();
    //是否找到大整數的最高有效位
    boolean findFirst = false;
    for(int i = result.length - 1; i >= 0; i--) {
        if(!findFirst) {
            if(result[i] == 0)
                continue;

            findFirst = true;
        }
        sb.append(result[i]);
    }
    
    return sb.toString();
 } 
 

 public static void main(String[] args) {
     System.out.println(bigNumberSum("426709752318", "95481253129"));
 }

我們來分析下這個算法的時間復雜度,如果給定的大整數的最長位數是n,那么創建數組、按位計算、結果逆序的時間復雜度均是O(n),因此整體時間復雜度是O(n)。

這個還有一個優化的地方。我們之前是把大整數按照每一個十進制數位來拆分,比如較大整數位的長度有50位,那么我們需要創建一個51位的數組,數組的每個元素均存儲一位。

我們真的有必要把整數拆得那么細嗎?很顯然沒必要。只需要拆分到可以被直接計算的程度即可。

我們都知道int類型的取值范圍是-2147483648~2147483647,最多有10位整數。為了防止溢出,我們可以把大整數的每9位作為數組的一個元素進行加法運算。

如此一來,占用空間和運算次數都被壓縮了9倍。其實,在Java中,工具類BigInteger和BigDecimal的底層實現也是把大整數拆分成數組進行運算,與此方法大體相同。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM