数据结构学习(三)队列

队列

ADT

顺序队列(循环队列)

template<class ElemType>    //顺序队列ADT
class SqQueue{  
   private:
      ElemType *elem;   // 存储空间基址
      int front;   // 队头指针
      int rear;   // 队尾指针
      int maxSize;        // 允许的最大存储容量(以sizeof(ElemType)为单位
   public:
      //初始化顺序队列
      SqQueue(int ms = 20){
        elem=new ElemType[ms];  <!-1
          maxSize=ms;
          front=rear=0;
      }
      //删除顺序队列
      ~SqQueue(){
          QueueDestroy();
        //   cout<<"what happend?";
      }
      //将顺序队列置为空
      bool QueueClear( ){
          front=rear;
          return 1;
      }
      //设置顺序栈的长度
      //bool SetListLength(int len);
      //判断顺序队列是否为空
      bool QueueisEmpty() const{ return front == rear; }
      //判断顺序队列是否为满
      bool QueueFull() const{ return front == (rear+1)%maxSize; }
      //用e返回队头元素
      bool GetFront(ElemType &e){
          if(front==rear)   //队列为空
            return 0;
          e=*(elem+front);
          return 1;
      }
      //返回队列长度
      int GetLen()const{ return (rear+maxSize-front)%maxSize; }
      //入队
      bool enQueue(const ElemType &e){
          if(QueueFull())
            return 0;
          *(elem+rear)=e;
        //   cout<<"!enQueue:"<<elem[rear]<<" ";
          rear=(rear+1)%maxSize;
          return 1;
      }
      //出队
      bool deQueue(ElemType &e){
          if(QueueisEmpty())
            return 0;
          e=*(elem+front);
        //   cout<<"!deQueue:"<<elem[front]<<" ";
          front=(front+1)%maxSize;
          return 1;  
      }
      //销毁顺序队列
      bool QueueDestroy(){
          if(!elem)
            return 0;   //指针为空,删除失败
          delete []elem;    //删除new出来的数组
        //   cout<<"why?";
          return 1;
      } 
      //顺序队列最大存储空间加倍
    //   bool DoubleSpace();
};
  • <!-1 语句 new ElemType[ms] 如果写成 new ElemType(ms) 会出现程序结束但不退出的情况,若使用delete语句并直接单步跳出(VScode)会报错:"Unknown stopping event"。

链队列(带头结点)

// 链队列结点
template<class ElemType>
struct LinkQueueNode
{
    ElemType data;
    LinkQueueNode<ElemType> *next;
    LinkQueueNode(LinkQueueNode<ElemType> *ptr = NULL){next = ptr;} //构造函数1,用于构造头结点
    LinkQueueNode(const ElemType &item, LinkQueueNode<ElemType> *ptr = NULL) //构造函数2,用于构造其他结点   
    //函数参数表中的形参允许有默认值,但是带默认值的参数需要放后面
    {
        next = ptr;
        data = item;
    }

    ElemType getData(){ return data;}  //取得结点中的数据

    void SetLink( LinkQueueNode<ElemType> *link ){ next = link; }  //修改结点的next域 

    void SetData( ElemType value ){ data = value; }   //修改结点的data域
};

//带头结点的链队列 
template<class ElemType>
class LinkQueue{
   private:
      LinkQueueNode<ElemType> *front;   // 队头指针
      LinkQueueNode<ElemType> *rear;   // 队尾指针
      int length;   //队列当前元素个数 

   public:
      //无参数的构造函数
      LinkQueue(){
          front=rear=new LinkQueueNode<ElemType>();
          length=0;
      }
      //析构函数
      ~LinkQueue(){LinkQueueDestroy();}
      //销毁链队列 
      bool LinkQueueDestroy(){
          LinkQueueNode<ElemType> *p=front,*p1;
          while(p){
              p1=p;
              p=p->next;
              delete p1;
          }
          front=rear=NULL;
          return 1;
      }
      //清空链表,只留下头结点
      bool LinkQueueClear(){
          LinkQueueNode<ElemType> *p=front->next,*p1;
          length=0;
          front->SetLink(NULL);
          rear=front;
          while(p){
              p1=p;
              p=p->next;
              delete p1;
          }
          return 1;
      }

      //返回链队列的长度
      int QueueLength() const{ return length;}
      //判断链队列是否为空队列
      bool QueueisEmpty() const{ return front==rear; }

      //出队
      bool deQueue( ElemType &e ){
          if(QueueisEmpty()) return 0;
          LinkQueueNode<ElemType> *p=front->next;
          e=p->getData();
          front->SetLink(p->next);
          length--;
          if(rear==p) rear=front;     //队列为空时头尾指针都在头结点上
          delete p;
          return 1;
      }
      //入队
      bool enQueue( ElemType e ){
          LinkQueueNode<ElemType> *p=new LinkQueueNode<ElemType>(e);
          rear->SetLink(p);
          rear=p;
          length++;
          return 1;
      }
      void upLength(){	//长度加一
          length++;
      }
      void downLength(){
          length--;
      }

      //获取链队列头结点指针 
      LinkQueueNode<ElemType>* GetFront()const{ return front;}
      //获取队头元素
      ElemType GetFrontData()const{ if(front->next) return front->next->data;}      
      //获取链队列队尾指针
      LinkQueueNode<ElemType>* GetRear()const{ return rear;}

      //遍历链队列 
      bool QueueTraverse(char ch) const{    //传入连接符号,不带换行
          if(QueueisEmpty()) return 0;
          LinkQueueNode<ElemType> *p=front->next;
          int c=0;
          while(p){
              if(c) cout<<ch;
              cout<<p->getData();
              p=p->next;
              c++;
          }
          return 1;
      }
      void queueReverse(){		//逆置队列
          if(length<=1) return;
          LinkQueueNode<ElemType> *p=front->next,*p1,*p2;
          front->SetLink(rear);
          p1=p->next;
          p->SetLink(NULL);
          rear=p;
          p2=p;
          p=p1;
          while(p){
              p1=p->next;
              p->SetLink(p2);
              p2=p;
              p=p1;
          }
          return ;
      }

};

函数(顺序队列)

杨辉三角

#include <iostream>

using namespace std;
//ADT
template<class ElemType>
void YangHuiTriangle(SqQueue<ElemType> &Q, int N){
    int c=0,a,b;
    for(int i=0;i<N;i++){
        if(i) cout<<endl;
        c=0;
        if(!Q.QueueisEmpty()){
            Q.deQueue(a);
            // cout<<" lenth="<<Q.GetLen();
        }
        for(int j=0;j<i+1;j++){
            if(!j || j%i==0){	//<!-1
                Q.enQueue(1);
                if(c) cout<<" ";
                cout<<1;
                // cout<<"!lenth="<<Q.GetLen()<<" ";
                c++;
            }
            else {
                Q.deQueue(b);
                Q.enQueue(a+b);
                if(c) cout<<" ";
                cout<<a+b;
                c++;
                a=b;
            }
        }
    }
    return ;
}

int main(){
    int n;
    cin>>n;
    SqQueue<int> q;
    YangHuiTriangle(q,n);
    // cout<<endl<<"end?";
    return 0;
}

思路是逐层将数字推入队列,碰到非端点则从队列中取出数字进行相加,一边输出一边用队列记录数字,从而代替数组。若上一层数量为 n(n!=1) ,则下一层正好要做 n-1 次相加,刚好将上一层队列推出,以此达到逐层计算的目的。

  • <!-1 如果括号内条件写成 j%i==0 会出现报错:"Arithmetic exception"。意为除数为零。

解码

应用:假设某国特工收到一串事先经过加密处理的密码数字(每位数字的范围为0-9),要求按照预先设定的规则将其解码,恢复到原始的状态,方可使用。解码规则如下:首先将第1位数删除,紧接着将第2位数放到这串数的末尾,再将第3位数删除,再将第4位数放到这串数的末尾,再将第5位数删除……直到剩下最后一位数,将最后一位数也删除。最后,按照刚才删除的顺序,把所有这些删除的数,按照删除的顺序重新连在一起就是原始的密码数字。
例如:给定的一串数字是“631758924”, 经过解码处理后,得到原始的密码数字为“615947283”。接收到的数字串内如存在空格,空格不计入位数。
template<class ElemType>
void decode(SqQueue<ElemType> &S, string &code){
    string s;
    s=code;
    int c=0;
    while(1){
        while(!S.QueueisEmpty()){
            char c;
            S.deQueue(c);
            s=s+c;
        }
        int k=s.length();
        if(k==1){
            cout<<s[0];
            break;
        }
        for(int i=0;i<k;i++){
            if(c%2){	//<!-1
                S.enQueue(s[i]);
                c++;
            }
            else{
                cout<<s[i];
                c++;
            }
        }
        s="";
    }
    return ;
}

int main(){
    string str,s,tmp;
    getline(cin,str);
    stringstream ss(str);
    while(ss>>tmp){     //去除空格
        s=s+tmp;
    }
    // cout<<s;
    SqQueue<char> q;
    decode(q,s);
    return 0;
}
  • <!-1 将数字接入字串末尾时奇偶计数是不重置的,所以不选用会重置的 i 作为判断变量,而是另外设置一个 c 全局不重置作为判断变量。

农夫过河

农夫、狼、白菜、羊要搭船去对岸,农夫驾船只能载其中一个,狼会吃羊,羊吃白菜,所以不能单独留在一岸;请求出一种合理的过河方式,使得全员到对岸,逆序输出驾船路径:

int route[16]={0};  //只用于标记有无涉及过

struct sta{     //定义状态
    int farmer;     //0在南岸,1在北岸
    int wolf;
    int cabbage;
    int goat;
    // int lasthash;   //默认为-1,也就是无前一结点
    sta(){};
    sta(int a,int b,int c,int d):farmer(a),wolf(b),cabbage(c),goat(d){}
    sta(int hash){      //根据哈希值生成
        goat=hash%2;
        hash/=2;
        cabbage=hash%2;
        hash/=2;
        wolf=hash%2;
        hash/=2;
        farmer=hash%2;
    }
    bool isSafe(){  //状态是否安全
        if(goat==wolf && goat!=farmer) return 0;
        if(goat==cabbage && goat!=farmer) return 0;
        return 1;
    }
    void output(){  //输出状态
        cout<<farmer<<wolf<<cabbage<<goat;
    }
    int getHash(){  //哈希
        int n=0;
        n+=goat*1;
        n+=cabbage*2;
        n+=wolf*4;
        n+=farmer*8;
        return n;
    }
    
};

template<class ElemType>
void farmerProblem(SqQueue<ElemType> &S){
    while(!S.QueueisEmpty()){
        sta s;
        S.deQueue(s);
        int n[4]={s.farmer,s.wolf,s.cabbage,s.goat};
        for(int i=3;i>0;i--){
            if(n[i]==n[0]){
                n[i]=1-n[i];    //状态转移
                n[0]=1-n[0];
                // cout<<"n="<<n[i]<<endl;
                sta tmp(n[0],n[1],n[2],n[3]);   //生成状态
                n[i]=1-n[i];    //状态回退
                n[0]=1-n[0];
                if(tmp.isSafe() && route[tmp.getHash()]==-1){  //未被访问且状态安全
                    route[tmp.getHash()]=s.getHash();
                    S.enQueue(tmp);
                }
            }
        }
        n[0]=1-n[0];    //考虑农夫独自过河,注意语句块与循环的位置关系啊..	<!-1
        sta tmp(n[0],n[1],n[2],n[3]);
        if(tmp.isSafe() && route[tmp.getHash()]==-1){
            route[tmp.getHash()]=s.getHash();
            S.enQueue(tmp);
        }
    }
    int a=15;
    while(a!=-2){
        int ss;
        sta tmp(a);
        tmp.output();
        cout<<endl;
        a=route[a];
    }
    return;
}



int main(){
    sta node(0,0,0,0);
    SqQueue<sta> q;
    for(int i=0;i<16;i++){
        route[i]=-1;
    }
    route[node.getHash()]=-2;   //标记起点
    q.enQueue(node);
    farmerProblem(q);
    return 0;
}

这题目真是给我恶心坏了...往队列里塞广搜,最重要的是它有两种解,OJ只判一种AC,我还以为是自己的顺序出问题,程序有BUG,整了半天,是真的吐了。

说说大体思路:用四位数组标记状态,0表示在南岸,1表示在北岸,不同位表示不同角色,利用进制转换将状态哈希后,用route数组保存到达该状态的前一状态,以此达到存储路径的目的,但在我看来广搜就不太适合保存路径...至少比深搜麻烦。这里我新建了结构体用于保存状态,方便推入队列和功能函数的封装,连带哈希、输出、安全性检查一起做进去相当省事,但是角色顺序因为题目没仔细看整了好久,弄得我头疼。随后通过广搜遍历安全且未访问的结点,遍历完后从终点开始回溯路径即可。需要注意的是我尝试用结构体保存路径,但是发现这样的操作类似于构造一条结构链,也就是保存上一结点信息来达到存储路径的效果,但是队列的推入很难保证地址不变,无法保存地址也就构造不了链表,该操作的实现就相当的复杂和困难(应该可以实现,但要用到指针的指针,可能相当麻烦)。所以最后仍然选择用全局数组取状态的哈希来保存路径并记录访问情况。

  • <!-1 这里我将该语句块放到了上方的循环中,导致农夫的状态量反复横跳出现了各种奇怪的状态变化,这个BUG解决的还算快,但确实恶心到我了,希望下次注意下次注意下次注意!

函数(链队列)

士兵队列训练

问题描述:先输入数据组数,每组数据输入士兵的人数n(默认从1到n给士兵编号),然后从前往后进行一、二报数,报到二的出列;剩下的人顺序不变,再进行一到三的报数,报到三的出列;剩下的人又一到二报数...重复以上过程,直到最后剩下的人数不超过三。(注意要在报数过程结束后再统计人数是否超过三)最后输出剩下的士兵编号:

const int newsol[2]={2,3};  //士兵出列报数

template<class ElemType>
void queuetraining(LinkQueue<ElemType> &S, int T){ 	//T为测试数据的组数
    while(T--){
        int n;
        cin>>n;
        S.LinkQueueClear();
        for(int i=0;i<n;i++){
            S.enQueue(i+1);     //士兵从1开始编号
        }
        int f=0,c=0;    //切换报数
        LinkQueueNode<ElemType> *p=S.GetFront()->next,*p1=S.GetFront();
        while(1){
            c++;
           // cout<<c<<endl;
            if(c%newsol[f]==0){
                p1->SetLink(p->next);
                // cout<<" x_"<<p->getData();
                delete p;
                p=p1->next;
                S.downLength();     //维护必要的长度
            } else {
                p1=p;
                p=p->next;
            }
            if(!p){
                if(S.QueueLength()<=3) break;
                p1=S.GetFront();
                p=p1->next;
                c=0;
                f=(f+1)%2;
            }
        }
        S.QueueTraverse(',');
        cout<<endl;
    }
    return ;
}

int main(){
    int n;
    cin>>n;
    LinkQueue<int> S;
    queuetraining(S,n);
    return 0;
}

因为把链队列的内部结构拆开使用了(所以链队列封装的意义何在..),有许多参数维护起来很麻烦,就偷懒没有维护尾指针,长度由于题目需要是必须维护的(一开始偷懒也没维护然后出错了233);这题有个注意的点是 S.QueueLength()<=3 判断语句要在每次报数结束后执行,而不能放到大的while循环中,否则人数一旦小于等于三就立刻退出了。

以上写法很不好,因为没有利用链队列的性质,拆封了结构,有更好的解决办法利用链队列的性质结构,简单阐述一下思路(懒得写了):每次报数时依次出列每一个士兵,未报到二或三的士兵再重新推入队列,这样未退出的士兵就会在上一轮报数的队列清空后按原有顺序添加在队尾,达到筛选的目的。这样也不用单独将链表结构拆出来使用。

猴子选大王(无头结点)

要求链队列无头结点,问题是约瑟夫环的猴王版,给定总数与淘汰数,输出最后剩下的:

#include <iostream>
#include <string>
using namespace std;

// 链队列结点
template<class ElemType>
struct LinkQueueNode
{
    ElemType data;
    LinkQueueNode<ElemType> *next;
    LinkQueueNode(LinkQueueNode<ElemType> *ptr = NULL){next = ptr;} //构造函数1,用于构造头结点
    LinkQueueNode(const ElemType &item, LinkQueueNode<ElemType> *ptr = NULL) //构造函数2,用于构造其他结点   
    //函数参数表中的形参允许有默认值,但是带默认值的参数需要放后面
    {
        next = ptr;
        data = item;
    }

    ElemType getData(){ return data;}  //取得结点中的数据

    void SetLink( LinkQueueNode<ElemType> *link ){ next = link; }  //修改结点的next域 

    void SetData( ElemType value ){ data = value; }   //修改结点的data域
};



//不带头结点的链队列 
template<class ElemType>
class LinkQueue{
   private:
      LinkQueueNode<ElemType> *front;   // 队头指针
      LinkQueueNode<ElemType> *rear;   // 队尾指针
      int length;   //队列当前元素个数 

   public:
      //无参数的构造函数
      LinkQueue(){
          front=rear=new LinkQueueNode<ElemType>;
          length=0;
      }
      //析构函数
      ~LinkQueue(){LinkQueueDestroy();}
      //销毁链队列 
      bool LinkQueueDestroy(){
          LinkQueueNode<ElemType> *p=front,*p1;
        //   cout<<endl<<length<<" ";
          while(p){
            //   cout<<p->getData()<<" ";
              p1=p;
              p=p->next;
              delete p1;
          }
          front=rear=NULL;
          return 1;
      }
      //返回链队列的长度
      int QueueLength() const{ return length;}
      //判断链队列是否为空队列,无头结点只能用长度判定
      bool QueueisEmpty() const{ return length==0; }

      //出队
      bool deQueue( ElemType &e ){
          if(QueueisEmpty()) return 0;
          LinkQueueNode<ElemType> *p=front;
          if(length==1){
              e=p->getData();
              length=0;
          } else {
              front=p->next;
              length--;
              e=p->getData();
              delete p;
          }
          return 1;
      }
      //入队
      bool enQueue( ElemType e ){
          if(length==0){
              front->SetData(e);
              length++;
              return 1;
          }
          LinkQueueNode<ElemType> *p=new LinkQueueNode<ElemType>(e);
          rear->SetLink(p);
          rear=p;
          length++;
          return 1;
      }
      void upLength(){
          length++;
      }
      void downLength(){
          length--;
      }

      //获取链队列s首指针 
      LinkQueueNode<ElemType>* GetFront()const{ return front;}
      //获取队头元素
      ElemType GetFrontData()const{ if(length) return front->data;}      
      //获取链队列队尾指针
      LinkQueueNode<ElemType>* GetRear()const{ return rear;}

      //遍历链队列 
      bool QueueTraverse(char ch) const{    //传入连接符号,不带换行
          if(QueueisEmpty()) return 0;
          LinkQueueNode<ElemType> *p=front;
          int c=0;
          while(p){
              if(c) cout<<ch;
              cout<<p->getData();
              p=p->next;
              c++;
          }
          return 1;
      }

};

template<class ElemType>
void monkey_king( LinkQueue<ElemType> &S, int n, int m ){	//<!-1
    for(int i=0;i<n;i++){
        S.enQueue(i+1);
    }
    int c=0;    //记录报数
    ElemType t;
    while(S.QueueLength()>1){
        c++;
        S.deQueue(t);
        if(c!=m){
            S.enQueue(t);
        } else {
            // cout<<t<<" "<<S.QueueLength()<<" ";
            c=0;
        }
    }
    S.QueueTraverse(',');
    cout<<" ";
    return ;
}

int main(){
    int n,m;
    cin>>n>>m;
    LinkQueue<int> S;
    monkey_king(S,n,m);
    return 0;
}

我不知道这个链队列有没有头结点对求解有什么影响,但我知道没有头结点这个链队列维护起来真的很麻烦。由于只是为了应付OJ,ADT只是敷衍了一下,别细究合理性。

  • <!-1 由于ADT没有特殊编写复制构造函数,这里如果参数不采用引用 &S 会出现链队列中的地址被删除两遍的问题,这是因为传参时新建了一个链队列,复制了一样的地址,函数结束后调用析构函数把地址全部情况,主函数结束后再清空一遍就出问题了,会报错"Unknown signal"。
    经过测试,哪怕在析构函数前判断头指针是否为空 if(!front) return 0; 也无法解决问题。

长整数加法计算

如其名,是之前链表题目的队列版,虽然我觉得挺多余的:

#include<iostream>
#include<sstream>
#include<string>
#include<string.h>
#include<iomanip>
using namespace std;

//链队列ADT

int string2int(string s){  //字符串转数字
    int k1=s.length();
    int c=0,f=1;
    for(int i=0;i<k1;i++){
       c+=f*(s[k1-1-i]-48);
       f*=10;
    }
    return c;
}
string Int_String( int result ){  //数字转字符串,由于锁死四位,不足要往左补0
    string s;
    while(result){
        s=char(result%10+48)+s;
        result/=10;
    }
    int k1=s.length();
    while(k1<4){
        s='0'+s;
        k1++;
    }
    return s;
}
template<class ElemType>
int Two_LongNum_Compare( LinkQueue<ElemType> &A, LinkQueue<ElemType> &B, const int &len_A, const int &len_B ){  //绝对值比较
    if(len_A>len_B) return 1;  //长度比较
    if(len_B>len_A) return 2;
    LinkQueueNode<ElemType> *p1=A.GetFront()->next,*p2=B.GetFront()->next;
    while(p1!=NULL){
        if(p1->data>p2->data) return 1;  //同步高位比大小
        if(p1->data<p2->data) return 2;
        p1=p1->next;
        p2=p2->next;
    }
    return 0;
}
template<class ElemType> 
void Input_Int_Division( LinkQueue<ElemType> &L, string &str, int &length ){  //分成四位一组
    int k1=str.length();  //取出长度
    if(str[0]=='-'){  //判断正负
        k1--;  //减去负号的长度
        L.GetFront()->SetData(-1);
        int cnt=1,res=k1%4;
        if(res) //如果为0就不要加项
        L.enQueue(string2int(str.substr(1,res)));
        for(int i=0;i<(k1-res)/4;i++){
            cnt++;
            L.enQueue(string2int(str.substr(res+1+4*i,4)));  //substr(string,pos,lenth)
        }
        length=cnt;  //块的数量
    } else {
        L.GetFront()->SetData(1);
        int cnt=1,res=k1%4;
        if(res) //如果为0就不要加项
            L.enQueue(string2int(str.substr(0,res)));  //前面非四个整的部分
        for(int i=0;i<(k1-res)/4;i++){
            cnt++;
            L.enQueue(string2int(str.substr(res+4*i,4)));
        }
        length=cnt;
    }
}
string noZero(string s)
{ //去除开头的0
    int i = 0;
    while (s[i] == 0)
    {
        i++;
    }
    return s.erase(0, i - 1);
}
template<class ElemType>
void Long_Int_enQueue( LinkQueue<ElemType> &A, LinkQueue<ElemType> &B, LinkQueue<ElemType> &C, const int &len_A, const int &len_B ){  //长整型相加
    if(!(A.GetFront()->data+B.GetFront()->data)){  //异号减法
        int tmp=Two_LongNum_Compare(A,B,len_A,len_B);
        A.queueReverse();
        B.queueReverse();
        LinkQueueNode<ElemType> *p1=A.GetFront()->next,*p2=B.GetFront()->next;
        if(tmp==1){  //A>B
            int f=0;  
            while(p1!=NULL && p2!=NULL){ 
                int c=p1->data-p2->data+f;  //减法
                f=0;
                if(c<0){  //借位
                    c+=10000;  
                    f=-1;  
                }
                C.enQueue(c);  //连接字符串
                p1=p1->next;  //迭代
                p2=p2->next;
            }
            while(p1!=NULL){
                int c=p1->data+f;  //上一个f可能为-1
                f=0;
                C.enQueue(c);  //直接推入链表中,enQueue为从尾巴添加,最后结果需要逆置
                p1=p1->next;
            }
            if(A.GetFront()->data==-1) C.GetFront()->SetData(-1);
            else C.GetFront()->SetData(1);  //设置符号位
        }
        if(tmp==2){  //B>A
            int f=0;
            while(p1!=NULL && p2!=NULL){  //同步
                int c=p2->data-p1->data+f;
              //  cout<<p2->data<<" - "<<p1->data<<" = "<<c<<endl;  //检测中间过程
                f=0;
                if(c<0){
                    c+=10000;
                    f=-1;  //借位
                }
                C.enQueue(c);  //添入链表
              //  cout<<result<<endl;
                p1=p1->next;
                p2=p2->next;
            }
            while(p2!=NULL){  //长出来的部分
                int c=p1->data+f;  //之前还留有的借位
                f=0;
                C.enQueue(c);
                p2=p2->next;
            }
            if(B.GetFront()->data==-1) C.GetFront()->SetData(-1);
            else C.GetFront()->SetData(1);
        }
        if(Two_LongNum_Compare(A,B,len_A,len_B)==0){  //B=A
             C.enQueue(0);
        }
        C.queueReverse();
    } else {  //同号
        A.queueReverse();  //反转
        B.queueReverse();
        LinkQueueNode<ElemType> *p1=A.GetFront()->next,*p2=B.GetFront()->next;  //反转后才能取首结点,表示从低位开始运算
        int f=0;
        while(p1!=NULL && p2!=NULL){
            int c=p2->data+p1->data+f;
            f=c/10000;  //进位
            c%=10000;
            C.enQueue(c);  //连接字符串
            p1=p1->next;  //迭代
            p2=p2->next;
        }
        while(p1!=NULL){  //如果A更长
            int c=p1->data+f;  
            f=0;
            C.enQueue(c);
            p1=p1->next;
        }
        while(p2!=NULL){  //如果B更长
            int c=p2->data+f;
            f=0;
            C.enQueue(c);
            p2=p2->next;
        }
        if(f){  //如果一样长但进位了
            C.enQueue(f);
        }
        if(B.GetFront()->data==-1) C.GetFront()->SetData(-1);  //如果为负
        else C.GetFront()->SetData(1);  
        C.queueReverse();
    }
}
template<class ElemType>
bool ListTraverse(LinkQueue<ElemType> &LInt){  //格式化遍历输出,注意除了第一节,后面的不足四位要往左边补0
    LinkQueueNode<ElemType> *p1=LInt.GetFront();
    if(p1->data==-1) cout<<"-";
    p1=p1->next;
    int c=0;
    while(p1!=NULL){  //cout补0是真的麻烦啊,所以可以利用Int_string转化补0,不需要补0的直接输出数字即可
        if(c) cout<<",";
        if(!c)
        cout << p1->data;
        else
        cout << Int_String(p1->data);
        p1=p1->next;
        c++;
    }
    cout<<endl;
    return 1;
}
int main(){
    string s,s_,sum;
    LinkQueue<int> L1,L2,L3;
    int l1,l2,l3;
    getline(cin,s);
    getline(cin,s_);
    Input_Int_Division(L1,s,l1);
    ListTraverse(L1);
    Input_Int_Division(L2,s_,l2);
    ListTraverse(L2);
    Long_Int_enQueue(L1,L2,L3,l1,l2);
    cout<<endl;
    ListTraverse(L3);
    return 0;
}

直接在之前链表的程序上换了个皮,ADT换一换,函数名称换一换,除了逆置函数重新编写了一遍,其他功能名字一换就搞定了= =,方便快捷,毕竟说到底就是个链表模型,当初实现的时候采用的就是链尾添加,需要出列的地方直接采用指针遍历效果也是一样的,所以修改起来相当方便。

posted @   Festu  阅读(138)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程
点击右上角即可分享
微信分享提示