1. 程式人生 > >資料結構-高精度大整數(一)

資料結構-高精度大整數(一)

每當我在C、C++語言中用到大整數的時候,都會羨慕Java的自帶大整數類的屬性。無奈只好自己動手,豐衣足食了。

從網上學習了大整數類的實現方法,覺得寫的挺好的,時間久了不記得從哪位大神的部落格裡學習的了...在這裡記錄一下自己的學習過程吧。

高精度大整數類:本類實現了大數的加減乘除四則運算,過載了輸入輸出運算子,冪運算,大於,小於,大於等於,小於等於,不等於等於,除法是整除,對餘數未確切定義,可以進一步完善,處理一些異常情況使得能夠更加通用.

輔助巨集:

#define POSITIZE 1 //正位(含0)
#define NEGATIVE -1 //負位

大整數類的定義:

struct BigInteger
{
    friend BigInteger operator - (BigInteger, BigInteger);
    friend BigInteger operator + (BigInteger, BigInteger);

   // 表示大數的結構。數位按低位到高位的順序存放。儲存的是數位值,而不是數位的字元值。
    vector<int> digits;  // 存放數位值
    int signbit;         // 符號位。

    BigInteger();
    BigInteger(long long int);
    void zero_justify();
    BigInteger operator ^  (int);
    BigInteger operator << (int);
    BigInteger operator += (const BigInteger &);
    BigInteger operator -= (const BigInteger &);
    BigInteger operator *= (const BigInteger &);
    BigInteger operator /= (const BigInteger &);
};
typedef BigInteger BI;

預設建構函式:

BigInteger::BigInteger()
{
    //預設建構函式
    signbit = POSITIZE;
}

大數類的建構函式 引數為長整數.

BigInteger::BigInteger(long long int a)
{
    //大數類的建構函式 引數為整數
    signbit = (a >= 0) ? POSITIZE:NEGATIVE;
    a = abs(a);

    do
    {
        digits.push_back(a % 10);
        a /= 10;
    }while(a);
}

過載輸入符號>>。

// 過載輸入符號>>。
istream & operator >> (istream & in, BigInteger &b)
{
     //讀入表示大整數的字串
    string s;
    in >> s;
    if(s.empty()) // 若長度為0,表示讀入的是一個空字串,應該要給予錯誤提示,並返回
        return in;

    /* 在解析之前,理應判斷該字串是否是一個合法的大數表示,即開始一位為符號位,為“+”或
     “-”,正整數“+”可以忽略,後面應該全部是數字字元,且不包含前導0*/
    // 解析符號位。
    if(isdigit(s[0]))
        b.signbit = POSITIZE;
    else
    {
        b.signbit = (s[0] == '+') ? POSITIZE:NEGATIVE;
        s.erase(s.begin());
    }
    // 解析數字位,從低位到高位存放於動態陣列中。
    b.digits.clear();
    for(int i = s.length() - 1; i >= 0; i--)
        b.digits.push_back(s[i] - '0');
    b.zero_justify();  //消除前導0

    return in;
}

過載輸出符號<<。

ostream & operator << (ostream &out, const BigInteger &b)
{
    // 當為自然數時,不輸出“+”號。
    if(b.signbit < 0)
        out << '-';
    for(int i = b.digits.size() - 1; i >= 0; i--)
        out << b.digits[i];

    return out;
}

移除大數運算產生的前導0。

void BigInteger::zero_justify()
{
    //移除大數運算產生的前導0。
    for(int i = digits.size() - 1; i >= 1; i--)
    {
        if(digits[i])
            break;
        else
            digits.pop_back();
    }
    if(digits.size() == 1 && digits[0] == 0) //只有一個0
        signbit = POSITIZE;
}

左移操作。n 表示左移的位數。即將 大數a 乘以 10^n。

BigInteger BigInteger::operator << (int n)
{
    // 左移操作。n 表示左移的位數。即將 a 乘以 10^n。
    // 若 a 等於 0,則移位後仍為 0。
    if(digits.size() == 1 && digits[0] == 0)
        return *this;
    // 向左移動 b 位,相當於在數位陣列前插入 n 個 0。
    for(int i = 0; i < n; i++)
        digits.insert(digits.begin(), 0);
    return *this;
}

比較兩個數的大小,若相等,返回 0,若 a 大於 b,返回 1,若 a 小於 b,返回 -1。

int compare(const BigInteger &a, const BigInteger &b)
{
    //比較兩個數的大小,若相等,返回 0,若 a 大於 b,返回 1,若 a 小於 b,返回 -1。
    // 若 a 為正,b 為負,則有 a 大於 b。
    if(a.signbit < b.signbit)
        return NEGATIVE;
    // 若 a 為負,b 為正,則 a 小於 b。
    else if(a.signbit > b.signbit)
        return POSITIZE;
    // 若兩數符號相同,則 a 的數位長度大於 b 的數位長度,若 a 為正數,則有 a 大於 b,若 a
    // 為負數,有 a 小於 b,則將 a 的符號位乘以1作為結果返回即可。
    if(a.digits.size() > b.digits.size())
        return a.signbit * POSITIZE;
      // 若兩數符號相同,若a的數位長度小於b的數位長度,若 a 為正數,則 a 小於 b,若 a 為負數,
      // 則 a 大於 b,則將 a 的符號位乘以 -1 作為結果返回即可。
    else if(a.digits.size() < b.digits.size())
        return a.signbit * NEGATIVE;

    // 兩個數的數位長度相等,符號相等,則從低位到高位逐個比較數位值的大小。
    for(int i = a.digits.size() - 1; i >= 0; i--)
    {
        if(a.digits[i] > b.digits[i])
            return a.signbit * POSITIZE;
        if(a.digits[i] < b.digits[i])
            return a.signbit * NEGATIVE;
    }

    return 0;
}

過載小於符.

bool operator < (const BigInteger &a, const BigInteger &b)
{
    //過載小於符
    return compare(a, b) < 0;
}

過載小於等於符.

bool operator <= (const BigInteger &a, const BigInteger &b)
{
    //過載小於等於符
    return compare(a, b) <= 0;
}

過載大於符.

bool operator > (const BigInteger &a, const BigInteger &b)
{
    //過載大於符
    return compare(a, b) > 0;
}

過載大於等於符.

bool operator >= (const BigInteger &a, const BigInteger &b)
{
    //過載大於等於符
    return compare(a, b) >= 0;
}

過載等於符.

bool operator == (const BigInteger &a, const BigInteger &b)
{
    //過載等於符
    return compare(a, b) == 0;
}

過載不等於符.

bool operator != (const BigInteger &a, const BigInteger &b)
{
    //過載不等於符
    return compare(a, b) != 0;
}

下一篇文章來具體講解關鍵的加減乘除等演算法的實現。