目录
1.题目
单链表ADT模板应用算法设计:长整数加法运算(不使用单链表存储计算结果)
作者: 冯向阳时间限制: 1S章节: DS:线性表
问题描述 :
目的:使用C++模板设计单链表的抽象数据类型(ADT)。并在此基础上,使用单链表ADT的基本操作,设计并实现单链表的应用算法设计。
内容:(1)请使用模板设计单链表的抽象数据类型。(由于该环境目前仅支持单文件的编译,故将所有内容都集中在一个源文件内。在实际的设计中,推荐将抽象类及对应的派生类分别放在单独的头文件中。参考网盘中的ADT原型文件。)
(2)ADT的应用:使用该ADT设计并实现单链表应用场合的算法设计。
应用:假设2个任意长度的整数x、y分别由带头结点的单链表A和B存储,现要求设计一个算法,实现任意长的整数进行加法运算,运算结果存储在字符串中。
参考函数原型:
template<class ElemType>
void Long_Int_Add( LinkList<ElemType> &A, LinkList<ElemType> &B, string &result, const int &len_A, const int &len_B );
辅助函数原型:
(1)从长整数的低位开始拆分(4位为一组,即不超过9999的非负整数),依次存放在单链表的每个结点的数据域中;头结点的数据域存放正负数标志(正数或0:1,负数:-1)。
template<class ElemType>
void Input_Int_Division( LinkList<ElemType> &L, string &str, int &length ); (length:长整数分割后的block数,恰为存储用单链表的长度)
(2)计算结果中间位格式控制
string Int_String( int result );
(3)两个长整数的绝对值大小比较(x>y 返回值为1;x<y 返回值为2;x=y 返回值为0;)
template<class ElemType>
int Two_LongNum_Compare( LinkList<ElemType> &A, LinkList<ElemType> &B, const int &len_A, const int &len_B );
(4)单链表ADT基本操作:单链表的逆置(实际计算时,鉴于单链表的顺序查找的特性,存储在单链表中的长整数需逆置,由原始的高位到低位排列,逆置为低位到高位降序排列。)
template<class ElemType>
void LinkList<ElemType>::ListReverse();
(5)单链表格式遍历:按照长整数的格式(4位为一组,组与组之间用,分隔)
template<class ElemType>
bool ListTraverse(LinkList<ElemType> &LInt)
输入说明 :
第一行:长整数x
第二行:长整数y
输出说明 :
第一行:格式化后的长整数x(从低位到高位每4位用","分开)
第二行:格式化后的长整数y(从低位到高位每4位用","分开)
第三行:空行
第四行:格式化后的计算结果(从低位到高位每4位用","分开)
(输入与输出之间用一空行分隔)
输入范例 :
-534564675768465476586798709880985345646757684654765867987098809853456467576846547658679870988098534564675768465476586798709880985345646757684654765867987098809853456467576846547658679870988098534564675768465476586798709880985345646757684654765867987098809853456467576846547658679870988098534564675768465476586798709880985345646757684654765867987098809853456467576846547658679870988098
435643754856985679435643754856985679435643754856985679435643754856985679435643754856985679435643754856985679435643754856985679435643754856985679435643754856985679435643754856985679435643754856985679435643754856985679435643754856985679435643754856985679输出范例 :
-5345,6467,5768,4654,7658,6798,7098,8098,5345,6467,5768,4654,7658,6798,7098,8098,5345,6467,5768,4654,7658,6798,7098,8098,5345,6467,5768,4654,7658,6798,7098,8098,5345,6467,5768,4654,7658,6798,7098,8098,5345,6467,5768,4654,7658,6798,7098,8098,5345,6467,5768,4654,7658,6798,7098,8098,5345,6467,5768,4654,7658,6798,7098,8098,5345,6467,5768,4654,7658,6798,7098,8098,5345,6467,5768,4654,7658,6798,7098,8098,5345,6467,5768,4654,7658,6798,7098,8098,5345,6467,5768,4654,7658,6798,7098,8098
4356,4375,4856,9856,7943,5643,7548,5698,5679,4356,4375,4856,9856,7943,5643,7548,5698,5679,4356,4375,4856,9856,7943,5643,7548,5698,5679,4356,4375,4856,9856,7943,5643,7548,5698,5679,4356,4375,4856,9856,7943,5643,7548,5698,5679,4356,4375,4856,9856,7943,5643,7548,5698,5679,4356,4375,4856,9856,7943,5643,7548,5698,5679-5345,6467,5768,4654,7658,6798,7098,8098,5345,6467,5768,4654,7658,6798,7098,8098,5345,6467,5768,4654,7658,6798,7098,8098,5345,6467,5768,4654,7658,6798,7098,8098,5345,2111,1392,9797,7801,8855,1455,0549,9647,0788,1412,0279,2801,6941,9155,2454,7797,0769,0089,0298,3283,1941,7242,0154,9701,8919,0069,8975,3302,2423,2241,8241,7402,0823,8219,8956,1979,2442,2723,3241,5488,8524,0124,7106,1960,1119,2742,3723,0488,6610,7824,9011,0110,1100,1419,3742,0970,1610,5911,6711,2014,9250,1400,2419
2.题解
- 挖坑
3.代码实现
- 完整代码
#include <iostream> #include <sstream> #include <vector> #include <cstring> using namespace std; string Int_String( int result ,int &num) { string str=""; char *Result=new char[4]; stringstream input; input<<result; input>>Result; input.clear(); if(result==0)str="0000"; else { if(result>0&&result<10)str="000"; if(result>9&&result<100)str="00"; if(result>99&&result<1000)str="0"; str.append(Result); } if(num>0)str.append(","); else num++; return str; } /* 单链表的结点定义 */ template<class ElemType> struct LinkNode { ElemType data; LinkNode<ElemType> *next; LinkNode(LinkNode<ElemType> *ptr = NULL){next = ptr;} LinkNode(const ElemType &item, LinkNode<ElemType> *ptr = NULL) //函数参数表中的形参允许有默认值,但是带默认值的参数需要放后面 { next = ptr; data = item; } }; //带头结点的单链表 template<class ElemType> class LinkList { private:; LinkNode<ElemType> *head; // 头指针 LinkNode<ElemType> *tail; // 尾指针 public: //无参数的构造函数 LinkList(){head = new LinkNode<ElemType>; tail =head;} //带参数的构造函数 LinkList(const ElemType &item){head = new LinkNode<ElemType>(item); tail = head;} //拷贝构造函数 LinkList(LinkList<ElemType> &List); //析构函数 ~LinkList(){ListDestroy();} //重载函数:赋值 LinkList<ElemType>& operator=(LinkList<ElemType> &List); //销毁链表 void ListDestroy(); //清空链表 void ListClear(); //返回链表的长度 int ListLength() const; //判断链表是否为空表 bool ListEmpty() const; //在首结点之前插入一个结点 bool InsFirst( ElemType &e ); //在尾结点之前插入一个结点 bool InsTail( ElemType &e ); //获取链表头指针 LinkNode<ElemType>* GetHead() const{ return head;} //获取链表尾指针 LinkNode<ElemType>* GetTail() const{ return tail;} //设置链表头指针 void SetHead(LinkNode<ElemType> *p){ head = p;} //设置链表尾指针 void SetTail(LinkNode<ElemType> *p){ tail = p;} //用e返回链表的第i个元素 ElemType GetElem(int pos); //在链表的第pos个位置之前插入e元素 bool ListInsert(int pos,ElemType e); //删除链表的首结点 //bool DelFirst( ElemType &e); //表头插入法动态生成链表 void CreateList_Head(vector<ElemType> &A); //表尾插入法动态生成链表 void CreateList_Tail(vector<ElemType> &A); //删除链表的第pos个位置的元素 ElemType ListDelete(int pos); //compare函数,用来判断a和b是否相等 //bool compare(ElemType a, ElemType *b); //按指定条件查找,返回指向第一个符合条件(=e)的元素的指针 bool LocateElem(const ElemType &e, LinkNode<ElemType> * &pos); //返回链表给定数据元素的前驱数据元素的值 //bool PriorElem(ElemType cur_e, ElemType &pri_e); //返回链表给定数据元素的后继数据元素的值 bool NextElem(LinkNode<ElemType> *p, ElemType &e); //遍历链表(老师写的是bool,为啥不是void) //bool ListTraverse() const; void ListTraverse() const; void ListReverse(); }; template<class ElemType> void LinkList<ElemType>::ListTraverse() const { if(head->data==-1)cout<<"-"; auto temp=head->next; while(temp) { string str; int num=0; if(temp==head->next)cout<<temp->data; else { str=Int_String(temp->data,num); cout<<str; } temp=temp->next; if(temp)cout<<","; } cout<<endl; } template<class ElemType> void LinkList<ElemType>::ListReverse() { auto pre=head; auto cur=pre->next; auto ne=cur; if(head->next==nullptr)return ; while(cur!=nullptr) { ne=cur->next; if(pre==head) { cur->next=nullptr; tail=cur; } else cur->next=pre; pre=cur; cur=ne; } head->next=pre; } template<class ElemType> void LinkList<ElemType>::ListDestroy() { auto temp=head; while(temp) { delete head; temp=temp->next; } } template<class ElemType> bool LinkList<ElemType>::InsFirst( ElemType &e ) { auto s=new LinkNode<ElemType>(e); s->next=head->next; head->next=s; if(s->next==nullptr)tail=s; return true; } template<class ElemType> void Input_Int_Division( LinkList<ElemType> &A, string &str, int &length ) { LinkNode<ElemType> *head; head=A.GetHead(); stringstream input; int len=str.length(); int s,temp; if(str.substr(0,1)=="-") { head->data=-1; str=str.substr(1,len); len=len-1; } else head->data=1; if(len%4)s=len/4+1; else s=len/4; length=s; if(len<=4) { input<<str; input>>temp; input.clear(); A.InsFirst(temp); } else { for(int i=1;i<=s;i++) { if(4*i<=len) { input<<str.substr(len-4*i,4); input>>temp; input.clear(); A.InsFirst(temp); } else { input<<str.substr(0,len-4*(i-1)); input>>temp; input.clear(); A.InsFirst(temp); } } } } template<class ElemType> int Two_LongNum_Compare( LinkList<ElemType> &A, LinkList<ElemType> &B, const int &lena, const int &lenb ) { LinkNode<ElemType> *pa,*pb; if(lena>lenb)return 1; else if(lena<lenb)return 2; else { pa=A.GetHead()->next; pb=B.GetHead()->next; while(pa) { if(pa->data > pb->data)return 1; else if(pa->data < pb->data)return 2; else { pa=pa->next; pb=pb->next; } } return 0; } } template<class ElemType> void Long_Int_Add( LinkList<ElemType> &A, LinkList<ElemType> &B, string &result, const int &len_A, const int &len_B ) { A.ListTraverse(); B.ListTraverse(); cout<<endl; //判断最终结果的正负性 auto ha=A.GetHead(); auto hb=B.GetHead(); auto fa=ha->data; auto fb=hb->data; int num_compare=Two_LongNum_Compare(A,B,len_A,len_B); int flag; if(fa==1&&fb==1)flag=0; if(fa==-1&&fb==-1)flag=1; if(fa==1&&fb==-1&&num_compare==1)flag=0; if(fa==1&&fb==-1&&num_compare==2)flag=1; if(fa==-1&&fb==1&&num_compare==1)flag=1; if(fa==-1&&fb==1&&num_compare==2)flag=0; if(fa!=fb&&num_compare==0){cout<<0<<endl;return;} //先把单链表逆置之后在进行加法运算 A.ListReverse(); B.ListReverse(); //长整数相加 int i;//last num int diga,digb;//every linknode num int tmp_res=0,tmp_res1=0,ff; int tmp=0;//add_sub to next num int finisha=0,finishb=0; int num=0;//about "," output ha=ha->next; hb=hb->next; while(!finisha||!finishb) { if(!finisha) { diga=ha->data; if(num_compare==2&&fa!=fb)diga=(-1)*ha->data; } else diga=0; if(!finishb) { digb=hb->data; if(num_compare==1&&fa!=fb)digb=(-1)*hb->data; } else digb=0; tmp_res=diga+digb+tmp; tmp=0; if(ha->next==nullptr)finisha=1; if(hb->next==nullptr)finishb=1; if(tmp_res>=10000&&(!finisha||!finishb)) { tmp=1; tmp_res-=10000; } if(tmp_res<0&&(!finisha||!finishb)) { tmp=-1; tmp_res+=10000; } //online calculate and store if(!finisha&&!finishb) result.insert(0,Int_String(tmp_res,num)); else { if(tmp_res==0&&result!=""){if(!(finisha&&finishb))result.insert(0,",");} else { if(result!="")result.insert(0,","); if(tmp_res>=10000) { tmp_res-=10000; int num1=0; string t=Int_String(tmp_res,num1); t+=result; result=t; result.insert(0,"1,"); } else { stringstream input; input<<tmp_res; string Result; input>>Result; input.clear(); result.insert(0,Result); } } } if(!finisha)ha=ha->next; if(!finishb)hb=hb->next; } if(flag)result.insert(0,"-"); } int main() { int lena,lenb; LinkList<int> A,B; string stra,strb; string res; getline(cin,stra); getline(cin,strb); Input_Int_Division(A,stra,lena); Input_Int_Division(B,strb,lenb); Long_Int_Add(A,B,res,lena,lenb); cout<<res<<endl; return 0; }