数据结构(一)——链表实现多项式的加法乘法(C++实现)

前言

作为日后必将成为大佬的 新手我来说,数据结构是一片崭新的领域,对它既有兴奋好奇,亦有担心疑虑。站在前人的肩膀上,他们告诉我,数据结构的意义=>link link
昨天一位学长(前端方向)面了字节,在面经中提到一点是面试官最后对学长的评价:
“觉得你可能太偏重于业务实现,或者把项目做出来就行了。或者你这个项目的深度根本就不够…需要去买书来系统性地学习下。比如说缓存,比如说跨域…是你必须了解的。”
这对我也是一种启示,光说不练假把式,反之亦然。理论联系实际,我期待着从项目中能不断深厚理论功底,这才能无往不胜啊!

链表

有机会链表专门写一篇,假装先留一个链接 [link] 溜了~

详情

方法

实现多项式加法乘法有三种方式:数组、链表、动态数组,其中动态数组是一种比较好的方法,但出于练习链表熟练度的目的,采用链表实现。自顶向下进行程序设计,在main函数中将有如下函数:

int main() {
 //读入p1、p2两个多项式,pp是加法结果,pm是乘法结果
 polynomial p1, p2, pp, pm;
 /*读入多项式
   以指数递减方式输入各项系数、指数
   各数间以空格隔开*/
 p1 = readpoly();
 p2 = readpoly();
 //多项式乘法
 pm = mult(p1, p2);
 //多项式加法
 pp = add(p1, p2);
 //以输入格式输出多项式
 print(pm);
 cout << endl;
 print(pp);
 cin.get();
 return 0;
}

其中我们强制规定输入时以指数递减方式输入多项式各项

定义数据结构

typedef struct polynode* polynomial;
struct polynode
{
 int coef;
 int expon;
 polynomial next;
};

建立链表结点结构体,并重新定义指向结点的指针为polynomial这种新的变量类型。在结点中保存coefficient(系数)、exponent(指数)两类int型数据和一个指向下一个结点的指针。
(使用typedef的好处:1.清晰表达,明白具体变量含义;2.使用方便;3.可移植性好。而这种新变量类型实质上是一种别名。)

函数实现

readpoly()及Attach()
//多项式的形成由它实现(串起来)
void Attach(int c,int e, polynomial* pRear)
{
   //开辟一个空节点
   polynomial p = new polynode;
   p->coef = c;
   p->expon = e;
   p->next = NULL;
   //*pRear是传入的rear指针,pRear是传入的rear指针的地址
   (*pRear)->next = p;
   *pRear = p;
}

polynomial readpoly()
{
   polynomial rear, t;
   polynomial p = new polynode;
   int c, e, n;
   rear = p;
   //读入多项式项数n
   cin >> n;
   while (n--) {
   //要求以指数递减方式输入
   cin >> c >> e;
   Attach(c, e, &rear);
 }
 t = p;
 p = p->next;
 delete(t);
 return p;
}

读入多项式要借助尾指针(rear)不断在链表尾部插入新的结点,这即要求rear始终指向表尾,也意味着rear要不停一项项后移至表尾。

首先我们开辟一个空结点,让p指向它,并让rear也指向这个空结点(rear = p)。然后我们在键盘输入多项式的项数n,利用while循环输入n项,每次输入格式要求指数递减,并利用Attach()函数连上各个结点。

Attach函数所需参数是c, e和指向rear的指针(why?因为形参、实参是值传递,要改变形参的值得传入地址,而此处显然需要改变rear指针的值) 在Attach函数中开辟一个空结点p,将c, e赋给结点,使next = NULL,并使(*pRear)即rear指针的next指向p,再让rear指向p实现rear始终在表尾。

最后有关键性一步就是将表头空结点删除,因为插入是在Attach中又构造一个新结点,所以表头始终是空的,要删去,此时需借助临时变量t。

add()
polynomial add(polynomial p1, polynomial p2)
{
 //开辟新结点用于存放要返回的加法结果
 polynomial p = new polynode;
 polynomial rear, t;
 p->next = NULL;
 rear = p;
 //当p1、p2都不空时
 while (p1 && p2) 
 {
  if (p1->expon == p2->expon) {
     //保证两系数相加不等于0再Attach
     if (p1->coef + p2->coef) {
        Attach(p1->coef + p2->coef, p1->expon, &rear);
     }
   p1 = p1->next;
   p2 = p2->next;
  }
  else if (p1->expon > p2->expon) {
     Attach(p1->coef, p1->expon, &rear);
     p1 = p1->next;
  }
  else {
     Attach(p2->coef, p2->expon, &rear);
     p2 = p2->next;
  }
 }
 //假如p2先加完了
 while (p1)
 {
    Attach(p1->coef, p1->expon, &rear);
    p1 = p1->next;
 }
 //假如p1先加完了
 while (p2) 
 {
    Attach(p2->coef, p2->expon, &rear);
    p2 = p2->next;
 }
 t = p;
 p = p->next;
 delete(t);
 return p;
}

加法的实现方法:
传入两个多项式(的头结点),开辟一个新的结点用于存放结果;三个while循环分别对应p1p2都不空,p1先加完剩p2,p2先加完剩p1;同时在p1p2都不空时,判断指数大小的三种情况,并在指数相等时,继续判断系数和是否为零,若为0则需要删除结点,若不为0则系数相加即可。
最后,同样的,要delete表头空结点。

mult()
/*乘法实现:
  先使p1的第一项乘以p2的每一项,
  再使p1第一项后的每一项乘以p2的每一项,再逐个插入链表*/
polynomial mult(polynomial p1, polynomial p2)
{
 polynomial p = new polynode;
 polynomial rear, t, t1, t2;
 int c, e;
 p->next = NULL;
 rear = p;
 //为什么需要这样?因为在第一次while中p2将指向最后一个节点,但之后仍需从头结点开始,故要让p2保留在指向头结点
 t1 = p1; t2 = p2;
 //判断有没有空多项式
 if (!t1 || !t2) return NULL;
 //先使p1的第一项乘以p2的每一项
 while (t2)
 {
    Attach(t1->coef * t2->coef, t1->expon + t2->expon, &rear);
    t2 = t2->next;
 }
 //指向p1的第二项
 t1 = t1->next;
 //再使p1第一项后的每一项乘以p2的每一项
 while (t1)
 {
    //让rear重新指向链表头空节点
    rear = p;
    t2 = p2;
   while (t2)
   {
     c = t1->coef * t2->coef;
     e = t1->expon + t2->expon;
     while (rear->next && rear->next->expon > e) rear = rear->next;
     //若两者指数相等
     if (rear->next && rear->next->expon == e) {
        //若且系数和不为零,则只改变系数
        if (rear->next->coef + c) {
           rear->next->coef += c;
        }
        //若且系数和为零,删除节点
        else {
          t = rear->next;
          rear->next = t->next;
          delete(t);
        }
     }
     //若插入项指数大于rear.next的指数,插入
     else {
       t = new polynode;
       t->coef = c;
       t->expon = e;
       t->next = rear->next;
       rear->next = t;
     }
    t2 = t2->next;
  }
   t1 = t1->next;
 }
 t = p;
 p = p->next;
 delete(t);
 return p;
}

乘法的实现方法:
一言以蔽之——逐项插入
先使p1第一项乘以p2每一项得到一组多项式(记为P0),之后p1第二项开始直到最后一项再分别与p2每一项相乘,得到的每一个项插入到P0中对应位置(满足指数递减排列)。
得到P0是比较容易的,系数相乘,指数相加,Attach串起来。

值得注意的是, 我们在这里有这么一步

 t1 = p1; t2 = p2;

原因是,我们在之后插入项到P0中时,每次都得从头结点一个个往后找,直到(下一个结点的指数)<=(要插入的项的指数),故得始终有一个指针指向头结点,在插入时让rear重新指回头结点,再一个个往后找。

//先使p1的第一项乘以p2的每一项
 while (t2)
 {
  Attach(t1->coef * t2->coef, t1->expon + t2->expon, &rear);
  t2 = t2->next;
 }
//先使p1的第一项乘以p2的每一项
 while (p2)
 {
  Attach(p1->coef * p2->coef, p1->expon + p2->expon, &rear);
  p2 = p2->next;
 }

比较以上,容易看到,若没有 t1=p1; t2=p2; 这两步,在第一次相乘时p2就已经指向到最后一个结点,之后rear就没法重新指回到p2的头结点了(p1亦然)。

再然后就是情况的讨论了,指数同系数和不为0改变系数,系数和为0删除结点;插入指数大则插入结点。

最后相同地,删去头结点。

print()
void print(polynomial p)
{
 //flag实现隔一个空格输出一个数
 int flag = 0;
 //若无多项式输出0 0
 if (!p) {
  cout << "0 0";
  return;
 }
 while (p) {
  if (!flag)flag = 1;
  else cout << " ";
  cout << p->coef << " " << p->expon;
  p = p->next;
 }
}

值得关注的点 就是利用flag自动实现每两个数间输出一个空格。

最后
希望有志于在大学期间掌握良好编程技能,或希望日后入职大型互联网公司或金融行业的同道中人能和我互关,交交朋友,毕竟,1+1>2嘛,大家一起进步啊!


2020/7/15 更新
麻烦大家收藏的同时也动动手指点赞呀,点赞会是对我最大的鼓励!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值