这一次整理了一下大整数类,学了算法设计上的大整数类,感觉挺不错的,但是不太懂,所以今晚照着网上的一个敲一下,因为我看懂了那个。
嘿嘿,借着这个机会也学一下STL中的队列
所谓大整数类,就是为了计算那些很大的数,如果这些数用一般的数据类型会发生溢出现象,无法计算,所以才引入了大整数类。
大整数类的运算原理:
模拟普通的竖式运算,然后考虑进位和借位。
存,数组或字符串
算,一位一位的算。
不要看着代码这么多,其实看懂了一个,基本上差不多
#include<iostream>
//#include"BigInteger/BigInteger.h"
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<deque>
#include<iterator>
#include<algorithm>
using namespace std;
typedef long long LLT;
//声明大整数类
class BigInteger
{
public:
//构造函数
BigInteger():num(), negative(false){}
BigInteger(const LLT);
BigInteger(const char *);
BigInteger(const string);
BigInteger(const BigInteger &x);
//运算及输入输出
BigInteger &operator =(const BigInteger &);
friend istream &operator >>(istream &,BigInteger &);
friend ostream &operator <<(ostream &,BigInteger);
//比较运算
bool operator > (const BigInteger &) const;
bool operator < (const BigInteger &) const;
bool operator == (const BigInteger &) const;
bool operator >= (const BigInteger &) const;
bool operator <= (const BigInteger &) const;
//绝对值与取反运算
friend const BigInteger abs(const BigInteger &);
const BigInteger operator - () const;
//四则运算
const BigInteger operator + (const BigInteger &) const;
const BigInteger operator - (const BigInteger &) const;
const BigInteger operator * (const BigInteger &) const;
const BigInteger operator / (const LLT &) const;
//取模运算
const LLT operator % (const LLT &) const;
private:
deque<int>num; //存那些数
bool negative; //确定符号
};
///相关定义
//构造函数
BigInteger::BigInteger(const LLT x)
{
LLT t=abs(x);
negative = x >= 0 ? false : true;
while(t > 0)
{
num.push_back(t % 10);
t /= 10;
}
}
BigInteger::BigInteger(const char* str)
{
unsigned i = str[0] == '-' ? 1 : 0;
this->negative = (str[0] == '-' ? true : false);
for(; i < strlen(str); i++)
num.push_back(str[i] - '0');
}
BigInteger::BigInteger(const string str)
{
unsigned i= str[0] == '-' ? 1 : 0;
this->negative = (str[0] == '0' ? true : false);
for(; i < str.length(); ++i)
{
num.push_back(str[i] - '0');
}
}
BigInteger::BigInteger(const BigInteger &x):num(x.num),negative(x.negative){}
//运算
BigInteger & BigInteger::operator = (const BigInteger &x)
{
negative = x.negative;
num = x.num;
return (*this);
}
istream & operator >> (istream & in, BigInteger &x)
{
string str;
in >> str;
x = str;
return in;
}
ostream & operator << (ostream &out, BigInteger x)
{
if(x.negative) out << '-';
for(unsigned i = 0; i != x.num.size(); i++)
out << x.num[i];
return out;
}
//比较运算
bool BigInteger:: operator > (const BigInteger & rhs) const
{
BigInteger x = (*this), y = rhs;
//讨论运算符
if(!x.negative && y.negative) return true; //x正y负
if(x.negative && !y.negative) return false; //x负y正
if(x.negative && y.negative) swap(x,y); //都是负的,交换
if(x.num.size() > y.num.size()) return true; //x的位数多
if(x.num.size() < y.num.size()) return false; //y的位数多
for(unsigned i = 0; i != x.num.size(); ++i)
{
if(x.num[i] > y.num[i]) return true;
if(x.num[i] < y.num[i]) return false;
}
return false;
}
bool BigInteger::operator < (const BigInteger & rhs) const
{
return rhs > *this;
}
bool BigInteger::operator == (const BigInteger & rhs) const
{
return negative ==rhs.negative && num == rhs.num;
}
bool BigInteger::operator >= (const BigInteger & rhs) const
{
return *this > rhs || *this ==rhs;
}
bool BigInteger::operator <= (const BigInteger & rhs) const
{
return rhs >= *this;
}
//取反与绝对值运算
const BigInteger abs(const BigInteger &rhs)
{
BigInteger res;
res.negative = false;
res.num = rhs.num;
return res;
}
const BigInteger BigInteger::operator - () const
{
BigInteger ret = *this;
ret.negative = !ret.negative;
return ret;
}
//四则运算
const BigInteger BigInteger::operator + (const BigInteger &y) const
{
//讨论符号
if(!this->negative && y.negative) return *this - abs(y);
if(this->negative && !y.negative) return y - abs(*this);
if(this->negative && y.negative) return -(abs(*this) + abs(y));
BigInteger x = *this, res;
int temp = 0;
for(int i = x.num.size() - 1, j = y.num.size();i >= 0||j >= 0;--i, --j) //加法运算原理 从最后一位两者相加,余数进队列,商进前一位
{
int a = i < 0 ? 0 : x.num[i];
int b = j < 0 ? 0 : y.num[j];
res.num.push_front((a + b + temp) % 10); //余数 往前放
temp = (a + b + temp) / 10; //商
}
if(temp != 0)
res.num.push_front(temp); //如果最后还有进位,放在最前面
return res;
}
const BigInteger BigInteger::operator - (const BigInteger &y) const //减法运算原理 绝对值运算,先倒过来,然后从第一位开始,上下相减,再重新遍历一遍,如果发现负的,加10,前一位减一
{
//讨论符号
if(!this->negative && y.negative) return *this + abs(y);
if(this->negative && !y.negative) return -(abs(*this)+y);
if(this->negative && y.negative) return abs(y)-abs(*this);
deque<int>a, b, res;
BigInteger ret;
copy(this->num.begin(), this->num.end(), front_inserter(a)); //倒过来
copy(y.num.begin(), y.num.end(), front_inserter(b));
if(y > *this)
{
swap(a, b); //绝对值大的放到a上
ret.negative = true;
}
res.resize(max(a.size(), b.size()) + 5); //重新定义队列的大小
for(unsigned i = 0, j = 0;i < a.size() || j < b.size(); ++i, ++j)
{
int m = i < a.size() ? a[i] : 0;
int n = j < b.size() ? b[i] : 0;
res[i] = m - n; //先减
}
for(unsigned i = 0;i < res.size()-1; ++i)
{
if(res[i] < 0)
{
res[i] = res[i] + 10; //如果发现负的,说明不够减,借位
res[i+1]--;
}
}
while (res.size() >= 2 && res.back() == 0) //后面的0去掉,因为待会要倒过来才是解,就成了前面的0了
{
res.pop_back();
}
reverse(res.begin(), res.end()); //倒过来得到答案
ret.num = res;
return ret;
}
const BigInteger BigInteger::operator * (const BigInteger &y) const //乘法原理 先不考虑进位,先存,相应的位相乘,得到最后的结果, 然后满十的往前进
{
deque<int>a, b, res;
copy(this->num.begin(), this->num.end(), front_inserter(a)); //倒过来
copy(y.num.begin(), y.num.end(), front_inserter(b));
res.resize(a.size() + b.size() + 5);
for(unsigned i = 0; i < a.size(); ++i)
for(unsigned j = 0; j<b.size(); ++j)
res[i+j] = res[i+j] + a[i] * b[j]; //相应的位上相乘,放好,这个时候没有考虑进位
for(unsigned i = 0; i < res.size() - 1; ++i)
{
res[i+1] = res[i+1] + res[i] / 10; //这个时候考虑进位
res[i] = res[i] % 10; //进位之后取余
}
while(res.size() && res.back() == 0) //去掉前面的0
res.pop_back();
reverse(res.begin(), res.end());
BigInteger ret;
ret.negative = this->negative ^ y.negative; //符号是两个数异或得来的
ret.num = res;
return ret;
}
const BigInteger BigInteger::operator / (const LLT & rhs) const //除法运算 从最低位开始,除,如果不够,加一位,再一次,慢慢的往高位
{
LLT temp = 0;
BigInteger x = (*this), res;
res.negative = this->negative ^ (rhs < 0 ? 1 : 0); //确定符号
int y = abs(rhs);
for(unsigned i = 0;i < x.num.size(); ++i)
{
temp = temp * 10 + x.num[i];
res.num.push_back((int)(temp / y));
temp %= y;
}
while (res.num.size() >= 2 && res.num.front() == 0) //把前面的0去掉
res.num.pop_front();
return res;
}
//取模运算
const LLT BigInteger::operator % (const LLT & y) const
{
LLT res = 0;
for(unsigned i = 0; i < this->num.size(); ++i)
res = (res * 10 + this->num[i]) % y;
return res;
}
//测试用
int main()
{
BigInteger a;
LLT b;
while(cin >> a >> b)
cout << a / b << endl;
return 0;
}
附加一个说明:
我上面头文件里面注释掉的那个,是我把大整数类的定义和实现封装到了一个头文件中,如果想用的话直接引入那个头文件即可,就是把那些定义啥的封装了起来,
就像这样,如果想封装的话,就需要自己定义一个头文件,然后把定义实现那些复制到头文件中,然后把头文件添加到codeblock路径中。下面我说一下怎么添加头文件到codeblock路径:
1.添加头文件:依次点击project->bulid options->Search directories,在该标签页中点击Compiler,单击Add按钮添加头文件路径