本学期数据结构课程设计的第一个作业。
初步想法:
使用FFTFFTFFT优化乘法
设nnn为大数的位数。
则乘法复杂度:O(n4log(n4))O(\frac{n}{4}log(\frac{n}{4}))O(4nlog(4n))
(压位处理,其中链表每一个节点存储四位数据)
除法则枚举答案的每一位,按位更新,复杂度O(n216)O(\frac{n^2}{16})O(16n2)
代码:(详细注释)
#include
#include
#include
#include
#include
using namespace std;
typedef int ElemType;
#define OK 1;
#define Error 0;
#define Wrong -1;
#define Over_Flow 0;
//双向循环链表实现部分
class LinkNode{ //链表结点
public:
ElemType data;
LinkNode *next,*prev;
};
class LinkList{ //带头节点的双向循环链表
public:
LinkNode *head;
int len;
};
void InitList(LinkList &L){ //初始化链表
L.len = 0;
L.head = new LinkNode;
L.head->next = L.head->prev = L.head;
}
void ClearList(LinkList &L){ //清空链表
LinkNode *p = L.head->next,*q;
while(p != L.head){
q = p->next;
delete p;
p = q;
}
L.head->next = L.head->prev = L.head;
L.len = 0;
}
void DestroyList(LinkList &L){ //销毁链表
ClearList(L);
delete L.head;
L.head = NULL;
}
bool ListEmpty(LinkList &L){ //判断链表是否为空
if(L.len) return false;
else return true;
}
ElemType ListLength(LinkList& L){ //求链表长度
return L.len;
}
bool InsertList(LinkList& L,ElemType data,int pos){ //在链表的第pos个位置之后插入数据data
if(pos<0 || pos>L.len) return Error; // 0 <= pos <= L.len
LinkNode *p = L.head;
if(pos <= L.len-pos+1){ //通过后继寻找位置
for(int i=1 ;i<=pos ;i++){
if(p == NULL) return Error;
p = p->next;
}
}
else{ //通过前驱寻找位置
for(int i=1 ;i<=L.len-pos+1 ;i++){
if(p == NULL) return Error;
p = p->prev;
}
}
LinkNode *q = new LinkNode;
q->data = data;
q->next = p->next;
q->prev = p;
p->next->prev = q;
p->next = q;
L.len++;
return OK;
}
bool QueryList(LinkList& L,int pos,ElemType& e){ //询问链表第pos个位置的值,通过e返回
if(pos<1 || pos>L.len) return Error; // 1 <= pos <= L.len
LinkNode *p = L.head;
if(pos <= L.len-pos+1){ //通过后继寻找位置
for(int i=1 ;i<=pos ;i++){
if(p == NULL) return Error;
p = p->next;
}
}
else{ //通过前驱寻找位置
for(int i=1 ;i<=L.len-pos+1 ;i++){
if(p == NULL) return Error;
p = p->prev;
}
}
e = p->data;
return OK;
}
bool DeleteList(LinkList &L,int pos,ElemType& e){ //删除第pos个位置的值,通过e返回
if(pos<1 || pos>L.len) return Error; // 1 <= pos <= L.len
LinkNode *p = L.head;
if(pos <= L.len-pos+1){ //通过后继寻找位置
for(int i=1 ;i<=pos ;i++){
if(p == NULL) return Error;
p = p->next;
}
}
else{ //通过前驱寻找位置
for(int i=1 ;i<=L.len-pos+1 ;i++){
if(p == NULL) return Error;
p = p->prev;
}
}
e = p->data;
p->prev->next = p->next;
p->next->prev = p->prev;
delete p;
L.len--;
return OK;
}
//四则运算部分
//输入部分
string s; //用于存储输入的大数
const ElemType mod = 10000;
//设定或者改变大数的符号
void BigInteger_Change_Symbol(LinkList &L,bool Positive){
if(Positive) L.head->data = 1;
else L.head->data = 0;
}
//输入大数
bool BigInteger_Input(LinkList &L){
InitList(L);
puts("Please input your Big_Integer(if negative, please add \"- \" before the number) :");
cin >> s;
int len = s.length();
if(len == 0) return Error;
ElemType data = 0;
int i = 0;
//设定大数符号
if(s[0] == '-'){
BigInteger_Change_Symbol(L,false);
i++;
}
else BigInteger_Change_Symbol(L,true);
for(;i<len ;i++){
if(s[i] == ','){
InsertList(L,data,0);
data = 0;
}
else{
data = data*10 + (s[i]-'0');
}
}
InsertList(L,data,0);
return OK;
}
//去掉大数的前导零
bool BigInteger_Delete_PreZero(LinkList& L){
LinkNode* p = L.head->prev,*q;
while(p!=L.head && !p->data){
L.len--;
p->prev->next = p->next;
p->next->prev = p->prev;
q = p->prev;
delete p;
p = q;
}
return OK;
}
//输出Big_Integer
bool BigInteger_Output(LinkList &L){
//负数特殊处理
if(L.head->data == 0) printf("-");
BigInteger_Delete_PreZero(L);
LinkNode* p = L.head->prev;
if(p == L.head){
printf("0");
return OK;
}
printf("%d",p->data);
while(p->prev != L.head){
p = p->prev;
printf(",%04d",p->data);
}
return OK;
}
//BigInteger 进位或者借位处理
bool BigInteger_Carry(LinkList& L){
if(L.len == 0) return Error;
LinkNode* p = L.head->next;
while(p->next != L.head){
if(p->data >= mod){ //需要进位
p->next->data += p->data/mod;
p->data %= mod;
}
while(p->data < 0){ //需要借位处理
p->next->data--;
p->data += mod;
}
p = p->next;
}
//最高位特殊处理(减法函数保证始终是大绝对值减小绝对值)
if(p->data >= mod){ //最高位进位
ElemType add = p->data/mod;
p->data %= mod;
InsertList(L,add,L.len);
}
return OK;
}
//求大数的位数
int BigInteger_Digit(LinkList& L){
if(L.len == 0) return 0;
int digit = (L.len-1)*4;
ElemType data = L.head->prev->data;
while(data){
digit++;
data /= 10;
}
return digit;
}
/*比较a,b的绝对值的大小
a>b 返回1
a=b 返回0
a
int BigInteger_Compare(LinkList& a,LinkList &b){
if(BigInteger_Digit(a) != BigInteger_Digit(b)){
if(BigInteger_Digit(a) > BigInteger_Digit(b)) return 1;
else return -1;
}
LinkNode* p = a.head->prev;
LinkNode* q = b.head->prev;
while(p != a.head && q != b.head){
if(p->data > q->data) return 1;
if(p->data < q->data) return -1;
p = p -> prev;
q = q -> prev;
}
return 0;
}
/*
四则运算部分说明:
1).因函数之间存在相互调用,如 (-a)-b = -(a+b) 和 a+(-b) = a-b 故运算函数在main函数后面实现
2).乘法使用FFT算法优化,设n为最大值的位数,则复杂度为: O((n/4)*log(n/4))
3).除法使用牛顿迭代法优化,复杂度同(2)中乘法操作*/
//计算Big_Integer a+b,结果用c返回
bool BigInteger_Add(LinkList a,LinkList b,LinkList& c);
//计算 Big_Integer a-b,结果用c返回
bool BigInteger_Minus(LinkList a,LinkList b,LinkList& c);
//计算Big_Integer a*b,结果用c返回
bool BigInteger_Multi(LinkList a,LinkList b,LinkList& c);
//计算Big_Integer a/b,结果用c返回
bool BigInteger_Division(LinkList a,LinkList b,LinkList& c);
//功能测试部分
LinkList a,b,c;
int main(){
//输入部分
if(!BigInteger_Input(a) || !BigInteger_Input(b)){
puts("Error in Input");
return 0;
}
//去掉前导零
BigInteger_Delete_PreZero(a);
BigInteger_Delete_PreZero(b);
//加法
puts("");
if(!BigInteger_Add(a,b,c)){
puts("Error in Add");
return 0;
}
puts("The result of Add: ");
BigInteger_Output(c);
//减法
puts("");
if(!BigInteger_Minus(a,b,c)){
puts("Error in Minus");
return 0;
}
puts("The result of Minus: ");
BigInteger_Output(c);
//乘法
puts("");
if(!BigInteger_Multi(a,b,c)){
puts("Error in Multi");
return 0;
}
puts("The result of Multi: ");
BigInteger_Output(c);
//除法
puts("");
if(!BigInteger_Division(a,b,c)){
puts("Error in Division");
return 0;
}
puts("The result of Division: ");
BigInteger_Output(c);
return 0;
}
//计算Big_Integer a+b,结果用c返回
bool BigInteger_Add(LinkList a,LinkList b,LinkList& c){
if(a.head->data && b.head->data){ //若a,b>0 则 c>0
InitList(c);
BigInteger_Change_Symbol(c,true);
}
else if(!(a.head->data) && !(b.head->data)){ //若a,b<0 则 c<0 且 |c| = |a| + |b|
InitList(c);
BigInteger_Change_Symbol(c,false);
}
else{
if(a.head->data){
BigInteger_Change_Symbol(b,true);
if(!BigInteger_Minus(a,b,c)) return Error;
}
else{
BigInteger_Change_Symbol(a,true);
if(!BigInteger_Minus(b,a,c)) return Error;
}
return OK;
}
LinkNode *p = a.head->next;
LinkNode *q = b.head->next;
while(p != a.head && q != b.head){
ElemType data = p->data + q->data;
InsertList(c,data,c.len);
p = p->next;
q = q->next;
}
while(p != a.head){
InsertList(c,p->data,c.len);
p = p->next;
}
while(q != b.head){
InsertList(c,q->data,c.len);
q = q->next;
}
BigInteger_Carry(c);
return OK;
}
//计算 Big_Integer a-b,结果用c返回
bool BigInteger_Minus(LinkList a,LinkList b,LinkList& c){
if(!a.head->data && b.head->data){
BigInteger_Change_Symbol(b,false);
if(!BigInteger_Add(a,b,c)) return Error;
return OK;
}
if(a.head->data && !b.head->data){
BigInteger_Change_Symbol(b,true);
if(!BigInteger_Add(a,b,c)) return Error;
return OK;
}
if(!a.head->data && !b.head->data){
BigInteger_Change_Symbol(a,true);
BigInteger_Change_Symbol(b,true);
swap(a,b);
}
InitList(c);
int mark = BigInteger_Compare(a,b);
if(mark == 1) BigInteger_Change_Symbol(c,true);
else if(mark == 0){
return OK;
}
else{
BigInteger_Change_Symbol(c,false);
swap(a,b);
}
LinkNode *p = a.head->next,*q = b.head->next;
while(p!=a.head && q!=b.head){
ElemType data = p->data - q->data;
InsertList(c,data,c.len);
p = p->next;
q = q->next;
}
while(p != a.head){
InsertList(c,p->data,c.len);
p = p->next;
}
BigInteger_Carry(c);
return OK;
}
//计算Big_Integer a*b,结果用c返回
//使用FFT优化,设n为最大值的位数,则复杂度为: O((n/4)*log(n/4))
//定义复数类
class Comp{
public:
double r,i;
Comp(double _r = 0,double _i = 0){r = _r;i = _i;}
Comp operator+(const Comp x){return Comp(r+x.r,i+x.i);}
Comp operator-(const Comp x){return Comp(r-x.r,i-x.i);}
Comp operator*(const Comp x){return Comp(r*x.r-i*x.i,r*x.i+i*x.r);}
}*x1,*x2;
//定义圆周率,用于求解单位复数根
const double PI = acos(-1.0);
//快速傅里叶变换的实现
void FFT(Comp a[],int n,int t){
for(int i=1,j=0; i<n-1 ;i++){
for(int s=n;j^=s>>=1,~j&s;);
if(i<j) swap(a[i],a[j]);
}
for(int d=0;(1<<d)<n ;d++){
int m = 1<<d,m2 = m<<1;
double o = PI/m*t;Comp _w(cos(o),sin(o));
for(int i=0 ;i<n ;i+=m2){
Comp w(1,0);
for(int j=0 ;j<m ;j++){
Comp &A = a[i+j+m],&B = a[i+j],t = w*A;
A = B-t;B = B+t;w = w*_w;
}
}
}
if(t==-1) for(int i=0 ;i<n ;i++) a[i].r/=n;
}
bool BigInteger_Multi(LinkList a,LinkList b,LinkList& c){
int n = 1; //快速傅里叶变换所需长度
while(n < a.len+b.len) n<<=1;
x1 = new Comp[n+10];
x2 = new Comp[n+10];
ElemType data;
for(int i=0 ;i<a.len ;i++){
QueryList(a,i+1,data);
x1[i] = Comp(data,0);
}
for(int i=a.len ;i<n ;i++) x1[i] = Comp(0,0);
for(int i=0 ;i<b.len ;i++){
QueryList(b,i+1,data);
x2[i] = Comp(data,0);
}
for(int i=b.len ;i<n ;i++) x2[i] = Comp(0,0);
FFT(x1,n,1);FFT(x2,n,1);
for(int i=0 ;i<n ;i++) x1[i] = x1[i]*x2[i];
FFT(x1,n,-1);
//判断结果的正负号
InitList(c);
if(a.head->data == b.head->data) BigInteger_Change_Symbol(c,true);
else BigInteger_Change_Symbol(c,false);
//保存结果
for(int i=0 ;i<n ;i++){
data = (ElemType)(x1[i].r + 0.5);
InsertList(c,data,c.len);
}
//进位
BigInteger_Carry(c);
//去掉前导0
BigInteger_Delete_PreZero(c);
return OK;
}
//计算Big_Integer a/b,结果用c返回
bool BigInteger_Division(LinkList a,LinkList b,LinkList& c){
if(b.len == 0) return Error;
if(BigInteger_Compare(a,b) == -1) return OK; //a
InitList(c);
//确定答案的正负号
if(a.head->data == b.head->data) BigInteger_Change_Symbol(c,true);
else BigInteger_Change_Symbol(c,false);
//取绝对值,方便减法运算
BigInteger_Change_Symbol(a,true);
BigInteger_Change_Symbol(b,true);
int add = BigInteger_Digit(a) - BigInteger_Digit(b);
LinkList d;InitList(d);BigInteger_Change_Symbol(d,true);
LinkList p;InitList(p);BigInteger_Change_Symbol(p,true);
for(int i=add ;i>=0 ;i--){
ClearList(d);BigInteger_Change_Symbol(d,true);
int now = i;
while(now>=4){
InsertList(d,0,0);
now -= 4;
}
if(now == 0) InsertList(d,1,d.len);
else if(now == 1) InsertList(d,10,d.len);
else if(now == 2) InsertList(d,100,d.len);
else InsertList(d,1000,d.len);
BigInteger_Multi(b,d,p);
while(BigInteger_Compare(a,p) != -1){
BigInteger_Minus(a,p,a);
BigInteger_Add(c,d,c);
BigInteger_Delete_PreZero(a);
}
}
BigInteger_Carry(c);
return OK;
}