27 单链表ADT模板应用算法设计:长整数加法运算(不使用单链表存储计算结果)
作者: 冯向阳时间限制: 1S章节: DS:线性表
晚于: 2021-04-18 23:55:00后提交分数乘系数50%
截止日期: 2021-04-18 23:55:00
问题描述 :
目的:使用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();
string 基本操作复习
// str.substr(int pos,int length);不修改原始字符串;
// string str1(string str0,int pos,int length);注意这里的length都是所需要赋值的长度;
// string& erase (size_t pos = 0, size_t len = npos);//仍然是从下标为零开始//
//#include<algorithm>.......reverse(str.begin(),str.end());
//str.insert(str.begin()+i,char c);
#include<iostream>
#include<string>
using namespace std;
int main()
{
string str;
cin>>str;
cout<<str.substr(1,str.length()-1);
string str1(str,1,str.length()-1);//注意这里'1',是数组下标哦//
cout<<str1<<endl;
str1.erase(0,str1.length());
cout<<str1<<endl;
str1=str1.erase(0,str1.length());
}
2.两个字符串自左向右逐个字符相比(按ASCII值大小相比较),直到出现不同的字符或遇’\0’为止。(string的大小比较),和数字的大小比较不一样
基本思路
具体代码
(如果您想优化我提供的代码块可以直接复制,修改后运行程序,看一看修改是否正确,方便最后的大程序调试的时候排除肯定正确的部分)
1. 函数实现之字符串格式化输出
#include<string>
#include<iostream>
using namespace std;
void show2( string str) //单纯只是格式化并且输出结果,值传递保证函数中的str不会影响到调用函数的地方//
{
if(str[0]=='-')
{
cout<<'-';
str.erase(0,1);
}
int len_str=str.length();
int yushu=len_str%4;
if(yushu==0)
yushu=4;
int flag=0;//标记是否是第一个输出的部分,来控制逗号输出格式//
for(;str[0];)
{ if(!flag)
{
cout<<str.substr(0,yushu);
str.erase(0,yushu);
flag=1;
}
else//避免str[i]==0问题,每次循环只进行一次输出//
{
cout<<","<<str.substr(0,4);
str=str.erase(0,4);
}
}
}
int main()
{
string str;
cin>>str;
show2(str);
}
2.函数实现之string转化成int(保证string没有负号的前提下)
#include<iostream>
using namespace std;
int str_int(const string &str)//将str按照它的正序转化为int类型//
{
int wei=1,result=0;;
for(int i=str.length()-1;i>=0;i--)//注意,str.length()==3,意味着最后面一个字符下标是2//
{
result+=(str[i]-'0')*wei;
wei=wei*10;
}
return result;
}
int main()
{
string str;
cin>>str;
cout<<str_int(str);
}
3.模板类实现,并且测试所有功能
#include<iostream>
using namespace std;
template<class ElemType>
struct Node
{
int data;
Node <ElemType>*next;
};
template<class ElemType>
class list_
{
private :
Node<ElemType>* head;
Node<ElemType>* tail;
public:
list_()//构造函数初始化头结点//
{
head=tail=new Node<ElemType>;
tail->next=NULL;
}
void set_(int num)//输入该链表正负信息//
{
head->data=num;
}
int Get_Set()//输出该链表正负信息//
{
return head->data;
}
void push_back_(ElemType data)//尾插(正序插入)//
{
Node<ElemType>* node=new Node<ElemType>;
node->data=data;
tail->next=node;
tail=node;
tail->next=NULL;
}
void push_front_(ElemType data)//头插(逆序插入)//
{
Node<ElemType>* node=new Node<ElemType>;
node->data=data;
node->next=head->next;
head->next=node;
if(node->next==NULL)//注意修改尾指针和把尾指针后面的指针域设置为空//
tail=node;
}
Node<ElemType>* NextPos_(Node<ElemType> *node)//获得下一个结点,保证node非空才可调用//
{
return node->next;
}
ElemType GetData_(Node<ElemType>* node)//获得节点的数据,保证node非空才可调用//
{
return node->data;
}
Node<ElemType>* GetHead_()//获得头结点//
{
return head;
}
};
template<class ElemType>
void display(list_<ElemType> L)
{
Node<ElemType>*node=L.GetHead_();
node=L.NextPos_(node);
cout<<"--正序输出链表--"<<endl;
while(node)
{
cout<<L.GetData_(node)<<endl;
node=L.NextPos_(node);
}
cout<<endl;
}
int main()
{
list_ <int>L;
L.push_front_(1);
L.push_front_(2);
L.push_front_(3);
L.set_(1314521);
cout<<"L.set_ "<<L.Get_Set()<<endl;
display<int>(L);
L.push_back_(1);
L.push_back_(2);
L.push_back_(3);
display<int>(L);
return 0;
}
4.函数实现之比较去掉正负号的string代表的int(也就是初始数据绝对值的大小)比较
#include<iostream>
using namespace std;
int setdaxiao(string a,string b) //a比b大应该是1,等于0,小于-1*这里的字符串是处理过没有负号的字符串//
{
int len_a=a.length();
int len_b=b.length();
if(len_a>len_b)
return 1;
else if(len_a<len_b)
return -1;
else//长度相同则可以逐个字符从前往后开始比较,符合string里面大于小于号的含义//
{
if(a>b)
return 1;
else if(a<b)
return -1;
else
return 0;
}
}
int main()
{
string str1,str2;//一定要输入正数,兄弟萌//
cin>>str1;
cin>>str2;
int daxiao=setdaxiao(str1,str2);
cout<<daxiao;
}
5.函数之输出符号与做加减法(具体逻辑和最后的程序一样,但是最后程序的简化版)
//特判: -100,100 ;0,0;0,100;100,0;0,-100;-100,0;-1,12;-12,13;-13,12;.....(关键注意最后是否需要输出负号也就是fuhao为负一)
#include<iostream>
using namespace std;
void SET_FF(int &fuhao,int &flag,int zf1,int zf2,int note)//结果为负,符号为负1,意味着要多输出一个负号,flag=2的时候做减法,flag=1的时候做加法//
{
if(zf1*zf2>0)
{
if(zf1<0)//两个均为负数//
{
fuhao=-1;
}
}
if(zf1*zf2<0)
{
flag=2;
if(zf1<0&¬e>0||zf2<0&¬e<0)//a,b异号但是不相等//
fuhao=-1;
}
}
int bijiao(string a,string b) //a比b大应该是1,等于为0,小于为-1*这里的字符串是处理过没有负号的字符串//
{
int len_a=a.length();
int len_b=b.length();
if(len_a>len_b)
return 1;
else if(len_a<len_b)
return -1;
else//长度相同则可以逐个字符从前往后开始比较,符合string里面大于小于号的含义//
{
if(a>b)
return 1;
else if(a<b)
return -1;
else
return 0;
}
}
int main()
{
string str1,str2;
getline(cin,str1);
getline(cin,str2);
int zf1=1;int zf2=1;
if(str1[0]=='-')
{
zf1=-1;
cout<<"zf1 "<<zf1<<endl;
str1.erase(0,1);
}
if(str2[0]=='-')
{
zf2=-1;
cout<<"zf2 "<<zf2<<endl;
str2.erase(0,1);
}
int note=bijiao(str1,str2);
cout<<"note "<<note<<endl;
int flag=1,fuhao=1;
SET_FF(fuhao,flag,zf1, zf2,note);
cout<<fuhao<<flag;
}
6.函数之将正数int->string
#include<iostream>
#include<algorithm>
using namespace std;
string int_str(int num)
{
string temp;
int i=0;
while(num)
{
char c=num%10-0+'0';
temp.insert(temp.begin(),c);//注意temp.insert(0,c)是错误的//
num=num/10;
i++;
}
return temp;
}
int main()
{
int num;
cin>>num;
string str=int_str(num);
cout<<str<<endl;
}
易错细节
1.做减法应该保证结果最前面不是零;
2.做加法应该考虑是否进位;
具体代码
里面的注释去掉后可以方便您查看到底程序处于什么位置
#include<iostream>
#include<string>
using namespace std;
template<class ElemType>
struct Node
{
int data;
Node <ElemType>*next;
};
template<class ElemType>
class list_
{
private :
Node<ElemType>* head;
Node<ElemType>* tail;
public:
list_()//构造函数初始化头结点//
{
head=tail=new Node<ElemType>;
tail->next=NULL;
}
void set_(int num)//输入该链表正负信息//
{
head->data=num;
}
int Get_Set()//输出该链表正负信息//
{
return head->data;
}
void push_back_(ElemType data)//尾插(正序插入)//
{
Node<ElemType>* node=new Node<ElemType>;
node->data=data;
tail->next=node;
tail=node;
tail->next=NULL;
}
void push_front_(ElemType data)//头插(逆序插入)//
{
Node<ElemType>* node=new Node<ElemType>;
node->data=data;
node->next=head->next;
head->next=node;
if(node->next==NULL)//注意修改尾指针和把尾指针后面的指针域设置为空//
tail=node;
}
Node<ElemType>* NextPos_(Node<ElemType> *node)//获得下一个结点,保证node非空才可调用//
{
return node->next;
}
ElemType GetData_(Node<ElemType>* node)//获得节点的数据,保证node非空才可调用//
{
return node->data;
}
Node<ElemType>* GetHead_()//获得头结点//
{
return head;
}
};
string int_str(int );
void reduce(string);
void fun(string&,string&,string&);
int bijiao(string a,string b) ;
int str_int(const string &str) ;
void show( string str);
void fun(string &a,string &b,string& result) ;
template<class ElemType>
void LongIntAdd(list_<ElemType> l1,list_<ElemType> l2,int note,string &result);
template<class ElemType>
void Add(list_<ElemType> l1,list_<ElemType> l2,string &result);
template<class ElemType>
void Min(list_<ElemType> l1,list_<ElemType> l2,string &result);
template<class ElemType>
void SET_FF(int &fuhao,int &flag,int note,list_<ElemType>l1,list_<ElemType>l2,int &huan,string &result);
template<class ElemType>
void show_Init(string &str,list_ <ElemType>&L);
template<class ElemType>
void Init(string &str,list_<ElemType> &L,int &yushu);
void reduce1(string& temp);
template<class ElemType>
void insert_(string temp,list_ <ElemType>&L);
string int_str(int num);
int bijiao(string a,string b) //a比b大应该是1,等于0,小于-1*这里的字符串是处理过没有负号的字符串//
{
int len_a=a.length();
int len_b=b.length();
if(len_a>len_b)
return 1;
else if(len_a<len_b)
return -1;
else//长度相同则可以逐个字符从前往后开始比较,符合string里面大于小于号的含义//
{
if(a>b)
return 1;
else if(a<b)
return -1;
else
return 0;
}
}
int str_int(const string &str)//将str按照它的正序转化为int类型//
{
int wei=1,result=0;;
for(int i=str.length()-1;i>=0;i--)//注意,str.length()==3,意味着最后面一个字符下标是2//
{
result+=(str[i]-'0')*wei;
wei=wei*10;
}
return result;
}
void show( string str) //单纯只是格式化并且输出结果,值传递保证函数中的str不会影响到调用函数的地方//
{
cout<<endl;
if(str[0]=='-')
{
cout<<'-';
str.erase(0,1);
}
int len_str=str.length();
int yushu=len_str%4;
if(yushu==0)
yushu=4;
int flag=0;//标记是否是第一个输出的部分,来控制逗号输出格式//
for(;str[0];)
{ if(!flag)
{
cout<<str.substr(0,yushu);
str.erase(0,yushu);
flag=1;
}
else//避免str[i]==0问题,每次循环只进行一次输出//
{
cout<<","<<str.substr(0,4);
str=str.erase(0,4);
}
}
cout<<endl;
}
template<class ElemType>
void fun(string &a,string &b,string& result)
{
getline(cin,a);
getline(cin,b);
list_<ElemType>l1;
list_<ElemType>l2;
show_Init(a,l1);
show_Init(b,l2);
int note=bijiao(a,b);//最主要的函数//
// cout<<"note "<<note<<endl;//
LongIntAdd(l1,l2,note,result);
}
template<class ElemType>
void LongIntAdd(list_<ElemType> l1,list_<ElemType> l2,int note,string &result)
{
int fuhao=1,flag=1,huan=0;//符号为1为正或零,为-1为负// //flag为一表示加法,为二表示减法//
SET_FF(fuhao,flag,note,l1,l2,huan,result); // cout<<"fuhao "<<fuhao<<"huan "<<huan<<endl;
if(flag==1)
Add(l1,l2,result);
else
{
if(!huan)
Min(l1,l2,result);
else
Min(l2,l1,result);
}
}
template<class ElemType>
void Add(list_<ElemType> l1,list_<ElemType> l2,string &result)
{
//cout<<"ADD"<<endl;//
string temp;int flag=0;
Node<ElemType>*node1=l1.NextPos_(l1.GetHead_());
Node<ElemType>*node2=l2.NextPos_(l2.GetHead_());
while(node1&&node2)
{
int sum=l1.GetData_(node1)+l2.GetData_(node2);
if(flag)
sum++;
if(sum>=10000)
{
sum=sum-10000;
flag=1;
}
else
flag=0;
string temp1=int_str(sum);
string temp2=temp1+temp;
temp=temp2;
node1=l1.NextPos_(node1);
node2=l2.NextPos_(node2);
}
while(node1)
{
int sum=l1.GetData_(node1);
if(flag)
sum++;
if(sum>=10000)
{
sum=sum-10000;
flag=1;
}
else
flag=0;
string temp1=int_str(sum);
string temp2=temp1+temp;
temp=temp2;
node1=l1.NextPos_(node1);
}
while(node2)
{
int sum=l2.GetData_(node2);
if(flag)
sum++;
if(sum>=10000)
{
sum=sum-10000;
flag=1;
}
else
flag=0;
string temp1=int_str(sum);
string temp2=temp1+temp;
temp=temp2;
node2=l2.NextPos_(node2);
}
if(flag)
{
string temp2="1"+temp;
temp=temp2;
}
reduce1(temp);
result=result+temp;
}
template<class ElemType>
void Min(list_<ElemType> l1,list_<ElemType> l2,string &result)
{
// cout<<"MIN"<<endl;//
string temp;int flag=0;
Node<ElemType>*node1=l1.NextPos_(l1.GetHead_());
Node<ElemType>*node2=l2.NextPos_(l2.GetHead_());
while(node1&&node2)
{
int sum=l1.GetData_(node1)-l2.GetData_(node2);
if(flag)
sum--;
if(sum<0)
{
sum=sum+10000;
flag=1;
}
else
flag=0;
string temp1=int_str(sum);
string temp2=temp1+temp;
temp=temp2;
node1=l1.NextPos_(node1);
node2=l2.NextPos_(node2);
}
while(node1)
{
int sum=l1.GetData_(node1);
if(flag)
sum--;
if(sum<0)
{
sum=sum+10000;
flag=1;
}
else
flag=0;
string temp1=int_str(sum);
string temp2=temp1+temp;
temp=temp2;
node1=l1.NextPos_(node1);
}
//cout<<temp<<" temp"<<endl;//
reduce1(temp);
result=result+temp;
//cout<<result<<" result"<<endl;//
}
void reduce1(string& temp)
{
//cout<<"&&&&"<<endl;//
while(true)
{
if(temp[0]!='0')//注意temp[0]!='0'不是temp[0]!=0//
break;
else
temp.erase(0,1);
//cout<<"********"<<endl;//
}
if(temp[0]==0)
temp+='0';//满足最后全为零的情况//
}
string int_str(int num)
{
string temp;
int i=0;
while(num)
{
char c=num%10-0+'0';
temp.insert(temp.begin(),c);//注意temp.insert(0,c)是错误的//
num=num/10;
i++;
}
int cha=4-temp.length();
temp.insert(0,cha,'0');
return temp;
}
template<class ElemType>
void SET_FF(int &fuhao,int &flag,int note,list_<ElemType>l1,list_<ElemType>l2,int &huan,string &result)
{
int zf1=l1.GetData_(l1.GetHead_());
int zf2=l2.GetData_(l2.GetHead_());
//cout<<"zf1 "<<zf1<<"zf2 "<<zf2<<endl;//
if(zf1*zf2>0)
{
if(zf1<0)
{
fuhao=-1;//两个都为负数//
}
}
if(zf1*zf2<0)
{
flag=2;
if(zf1<0&¬e==1||zf2<0&¬e==-1)
{
fuhao=-1;//一个负数比一个正数大//
}
if(note<0)
huan=1;
}
if(fuhao==-1)
result+="-";
}
template<class ElemType>
void show_Init(string &str,list_ <ElemType>&L)//格式化输出初始字符串并且创建链表,与函数show()唯一的区别就是增加一个insert_()函数的调用//
{
int yushu;
Init(str,L,yushu);//删除字符串前面的负号并且保存在头结点中并且输出,同时返回余数//
string str1=str;//注意循环结束条件是str为空,所以不能破坏原有的string//
for(int flag=0;str1[0];)
{
if(!flag)//flag标记第一个最前面的yushu个数字输出//
{
string temp=str1.substr(0,yushu);
cout<<temp;
insert_(temp,L);//将这个字符串转化成int类型整数后头插到带有头结点的单链表里//
str1=str1.erase(0,yushu);
flag=1;
}
else
{
string temp=str1.substr(0,4);
cout<<","<<temp;
insert_(temp,L);
str1=str1.erase(0,4);
}
}
cout<<endl;
}
template<class ElemType>
void Init(string &str,list_<ElemType> &L,int &yushu)//创建链表头结点并且删除本来含符号的第一项,引用类型传递余数长度等信息,注意零保存的是+1//
{
if(str[0]=='-')
{
str=str.substr(1,str.length()-1);
L.set_(-1);
cout<<"-";
}
else
L.set_(1);
yushu=str.length()%4;
if(!yushu)//余数为零设置为四//
yushu=4;
//cout<<"str is "<<str<<endl;//
}
template<class ElemType>
void insert_(string temp,list_ <ElemType>&L)//将这一小段string temp转化为int 头插入链表//
{
int num=str_int(temp);
L.push_front_(num);
}
int main()
{
string a,b,result;
fun<int>(a,b,result);
show(result);
}