DHU-数据结构-单链表-ADT应用-长整数加法运算

目录

1.题目

2.题解

3.代码实现


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;
    }
    

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值