資料結構-高精度大整數(一)
阿新 • • 發佈:2018-12-16
每當我在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;
}
下一篇文章來具體講解關鍵的加減乘除等演算法的實現。