链表实现两个多项式的加法

最近遇到这样一个题目,使用链表来实现两个多项式的加法,刚开始觉得应该比较简单,也可能是自己基础不扎实吧,这其中也是踩了很多的坑啊,最终还是成功了,特此写博客记录一下。

一、题目要求

使用链表来实现两个多项式的加法,输出最终相加后的多项式。多项式默认是按指数(幂次)依次递增的,输入时会依次输入每一项的系数和指数,两个多项式之间的数据以连续两个0来结束一个多项式的输入,最终输出两个多项式相加的多项式结果。例如:

多项式A: X^1 + 2 * X^2 + 3 * X^3
多项式B: X^1 + 2 * X^2 + 3 * X^3

输入:

1 1
2 2
3 3
0 0
1 1
2 2
3 3
0 0

输出:

2 * X^1 + 4 * X^2 + 6 * X^3

上面便是题目的要求,下面我们开始正式分析。

二、题目分析

我们先要解决的问题是多项式的存储问题,即它在计算机中的表现形式,很明显我们只需要存储了多项式的系数和指数即可以开始后面加法计算。这里我们又两种存储方式,一种是线性存储,另一种是链式存储。

线性存储,比如我们采用数组来存储这些数据,理论来说是可以的,但是由于我们的多项式的项数是不确定的,但数组必须在刚开始就必须
先给定一个初始的大小,这个初始大小我们不好确定,分配少了,没法存储全部多项式,分配多了,会造成空间浪费,所以我们在这里采用链表来存储多项式,每次输入一个多项式节点,我们就分配一个链表的节点,这样便可以合理的节约空间。

接着我们分析的是具体的实现步骤,我在这里将其分为三步:

第一步:
接收用户控制台的输入,并且生成对应的两个多项式的链表表示。

我们的每个链表节点有三个域,前两个域是数据域,依次表示多项式的系数和指数,第三个域是指针域,指向下一个节点
这里我们为了方便后续处理,给每个连边增加一个头结点,头结点的数据域内都放-1,没有实际意义。如下图所示:


头结点

第二步:
依次对两个链表中的数据进行加法处理

这一步是我们的关键步骤,下面将以图文结合的方式来进行解释:

链表加法

如图中所示,我们准备了A、B两个链表

链表A表示的多项式: 7 * X^1 + 2 * X^2 + 8 * X^5
链表B表示的多项式: 2 * X^1 + (-2 * X^2) + 2 * X^3
链表C是我们最终的和链表

这里我们按照这样的步骤进行处理:

1 . 我们规定三个头指针,分别指向三个链表的头,然后再规定三个移动指针,分别指向当前三个链表中正在处理的那个节点

2 . 我们让A、B、C的移动指针刚开始也处于头指针的位置,然后,我们拿A第一个节点中的指数和B第一个节点中的指数进行比较,这个时候有三种情况:

a情况 . A中当前的节点指数 < B中当前的节点指数 ------ 我们将A中的当前节点插入C中,然后向后移动A和C的指针(因为A中当前节点已经处理了)

b情况 . A中当前的节点指数 > B中当前的节点指数 ------ 我们将B中的当前节点插入C中,然后向后移动B和C的指针(因为B中当前节点已经处理了) 即图中⑧的情况。

c情况 . A中当前的节点指数 > B中当前的节点指数 ------ 此时A和B当前节点指数相同,可以进行系数相加,这时候也会出现两种情况:

情况1 . 系数之和不为0 ------ 我们此时将系数之和放到A中的当前节点的系数域,然后将A中的该节点插入C中,然后向后移动C的指针(记住,我们这里不是产生一个新的节点,而是直接更改A的系数域,然后将A的当前节点插入C中),即图中的①和②产生③的过程。

情况2 . 系数之和为0 ------ 此时我们不能将系数和为0的项放入链表C中,理论来说我们什么都不用做,但是这里有一个小问题,因为按照情况1来看,我们在系数和不为0时是将A节点直接插到C中,我们假设我们在系数和为0后什么都不做,继续处理A中后续节点,后面遇到一个系数和不为0的情况,我们将后面遇到的这个系数不为0的节点插入C中,那其实也将前面那个系数为0的项也一并插入C中了,以为前面那个系数为0的节点和其他后面的节点一直保持联系。所以我们此时必须在系数和为0时,将A中的当前节点删除了。即图中的④和⑤产生⑥的过程。

无论上面是情况1还是情况2,总之我们都同时处理了节点A和节点B,所以,我们还需要同时将节点A和B的移动指针向后移动。

这里还有一个情况,我们的A、B链表可能长度不是一致的,那么就有可能其中一个链表的移动指针已经移动到了末尾,那么此时,我们就不需要继续移动了,我们只需要将另一个链表中未处理的数据直接接在当前已经生产的C链表的后面即可。

第三步:
打印输出最终计算所得的和链表表达式

三、代码实现

经过上面的分析,我们这里分别采用C语言和Java来实现上述思路,代码中有详细的注释,下面只进行简单解释。

C语言实现:

#include<stdio.h>
#include<malloc.h>
typedef struct node{
    float coef;
    int expn;
    node *next;
}Lnode, * Dxs;

Dxs create();
Dxs add_dxs(Dxs firsta, Dxs firstb);
void printDxs(Dxs h);
void deleteNode(Dxs h, Dxs p);


int main(){
    Dxs ha, hb, hc;
    printf("请依次输入第一个多项式的系数和指数\n");
    ha = create();
    printf("请依次输入第二个多项式的系数和指数\n");
    hb = create();
    printf("输入的第一个多项式是: ");
    printDxs(ha->next);
    printf("输入的第二个多项式是: ");
    printDxs(hb->next);
    hc = add_dxs(ha, hb);
    printf("两个多项式的和为: ");
    printDxs(hc->next);
    return 0;
}

//创建链表(读入数据以 0 0 结束)
Dxs create(){
    float coef;
    int expn;
    Dxs first, qa, s;
    first = (Dxs)malloc(sizeof(Lnode));
    first->coef = -1;
    first->expn = -1;
    first->next = NULL;
    qa = first;
    while(1){
        scanf("%f", &coef);
        scanf("%d", &expn);
        if(coef == 0 && expn == 0){
            break;
        }
        s = (Dxs)malloc(sizeof(Lnode));
        s->coef = coef;
        s->expn = expn;
        s->next = NULL;
        qa->next = s;
        qa = s;
    }
    return first;
}

//链表相加
Dxs add_dxs(Dxs firsta, Dxs firstb){
    Dxs firstc, ha, hb, pc, s;
    int a, b;
    float sum;
    firstc = (Dxs)malloc(sizeof(Lnode));
    firstc->coef = -1;
    firstc->expn = -1;
    firstc->next = NULL;
    pc = firstc;

    ha = firsta->next;
    hb = firstb->next;
    while(ha!= NULL && hb != NULL){
        a = ha->expn;
        b = hb->expn;
        if(a < b){
            //将a加入c中,移动a和c的指针
            pc->next = ha;
            pc = pc->next;
            ha = ha->next;
        }else if(a > b){
            //将b加入c中,移动b和c的指针
            pc->next = hb;
            pc = pc->next;
            hb = hb->next;
        }else{
            sum = ha->coef + hb->coef;
            if(sum != 0.0){
                //将和加入a中,再将a加入c中,移动c的指针
                ha->coef = sum;
                pc->next = ha;
                pc = pc->next;
            }else{

                //查找删除A中系数之和为0的那个节点
                s = firsta;
                while(s != ha){
                    s = s->next;
                }
                s->next = ha->next;
            }
            //ab已经处理完成,同时后移一位
            ha = ha->next;
            hb = hb->next;
        }
    }

    //将剩余部分加入c后面
    if(ha != NULL){
        pc->next = ha;
    }

    if(hb != NULL){
        pc->next = hb;
    }
    return firstc;
}

//遍历显示链表
void printDxs(Dxs h){
    while(h != NULL){
        printf("%0.2f*X^%d + ", h->coef, h->expn);
        h=h->next;
    }
    printf("\n");
}

Java语言描述:

package cn.codekong;

import java.util.Scanner;

/**
 * 链表类
 * @author szh
 *
 */
public class MyLink {

    /**
     * 链表节点类
     * @author szh
     *
     */
    class Node{
        //多项式的系数
        private float coef;
        //多项式的指数
        private int expn;
        //指向下级节点
        public Node next = null;
        public Node(float coef, int expn){
            this.coef = coef;
            this.expn = expn;
        }
    }

    /**
     * 创建链表类
     * 从从控制台不断读入数据,以(0 0)结束
     * @return  创建好链表的第一个节点
     */
    public Node createLink(){
        //存取从控制台读到的系数和指数
        float coef = 0.0f;
        int expn = 0;
        //头尾节点(尾节点方便插入)
        Node head, tail;
        head= new Node(-1, -1);
        head.next = null;
        tail = head;
        Scanner scanner = new Scanner(System.in);
        while(true){
            String res = scanner.nextLine();
            //以空格分割一行中的字符串
            String[] resArray = res.split("\\s+");
            coef = Float.parseFloat(resArray[0]);
            expn = Integer.parseInt(resArray[1]);
            if(coef == 0 && expn == 0.0f){
                break;
            }
            Node node = new Node(coef, expn);
            node.next = null;
            tail.next = node;
            tail = tail.next;
        }
        return head;
    }


    /**
     * 打印链表
     * @param head 链表首节点
     */
    public void printLink(Node head){
        while(head != null){
            System.out.format("%.2f*X^%d + ", head.coef, head.expn);
            head = head.next;
        }
        System.out.println();
    }

    /**
     * 计算两个链表的和
     * @param nodeA
     * @param nodeB
     * @return  最终和的链表
     */
    public Node addLink(Node nodeA, Node nodeB){
        Node nodeC = new Node(-1, -1);
        nodeC.next = null;
        //始终指向链表的当前需要处理的节点(刚开始要除去开头的(-1,-1)节点)
        Node pA = nodeA.next, pB = nodeB.next, pC = nodeC;
        //当前指向的两个链表的指数
        int valueAExpn = 0, valueBExpn = 0;
        while(pA != null && pB != null){
            valueAExpn = pA.expn;
            valueBExpn = pB.expn;
            if(valueAExpn < valueBExpn){
                //将A中的该节点加入C中, 同时移动A和C的指针指向下个元素
                pC.next = pA;
                pC = pC.next;
                pA = pA.next;
            }else if(valueAExpn > valueBExpn){
                //将B中的该节点加入C中,同时移动B和C的指针指向下个元素
                pC.next = pB;
                pC = pC.next;
                pB = pB.next;
            }else{
                //两节点指数相同
                //现将系数相加放到A节点的系数中,然后将A节点加入C中
                float sum = pA.coef + pB.coef;
                if(sum != 0.0f){
                    //系数和不为0,将A节点的系数改变为sum,然后将A节点加入C中
                    pA.coef = sum;
                    pC.next = pA;
                    pC = pC.next;
                }else{
                    //系数和为0,必须将A链表中的该节点从链表中删除掉,如果只移动指针,会在输出时也输出该项
                    //在整个A链表中依次查找,必须找到要删除节点的前驱节点才能将其删除
                    Node s = nodeA;
                    while(s != pA){
                        s = s.next;
                    }
                    //删除该节点
                    s.next = pA.next;
                }
                //对于系数相同的情况,A和B节点指针都往后移动
                pA = pA.next;
                pB = pB.next;
            }
        }
        if(pA != null){
            pC.next = pA;
        }
        if(pB != null){
            pC.next = pB;
        }
        return nodeC;
    }
}
package cn.codekong;

import cn.codekong.MyLink.Node;

public class MyTest {
    public static void main(String[] args) {
        MyLink myLink = new MyLink();
        System.out.println("请依次输入第一个多项式的系数和指数");
        Node nodea = myLink.createLink();
        System.out.println("请依次输入第二个多项式的系数和指数");
        Node nodeb = myLink.createLink();
        System.out.println("输入的第一个多项式是: ");
        myLink.printLink(nodea.next);
        System.out.println("输入的第二个多项式是: ");
        myLink.printLink(nodeb.next);
        Node nodec = myLink.addLink(nodea, nodeb);
        System.out.println("两个多项式的和为: ");
        myLink.printLink(nodec.next);
    }
}

其实Java的链表实现和C语言很类似,只是C语言中的节点是定义结构体,而此处是使用一个内部类来定义链表的每个节点,C语言中的指针其实就是Java中的引用,我们生命的Java对象是存储在堆中,而对象的引用则是存储在堆栈中。

上面为了保持Java和C在控制台输入的一致性,我通过使用Scanner读入一行,然后通过正则表达式分割出系数和指数进行后续处理。

四、代码运行验证

C语言运行结果:


C语言运行结果

Java运行结果:


Java运行结果
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容

  • 1 序 2016年6月25日夜,帝都,天下着大雨,拖着行李箱和同学在校门口照了最后一张合照,搬离寝室打车去了提前租...
    RichardJieChen阅读 5,016评论 0 12
  • 实验内容 需要设计一个简单的一元稀疏多项式加减法计算器 实验要求 输入并建立多项式 例如:![][1][1]: h...
    我叫卡卡算了阅读 2,483评论 0 9
  • 如果要用语言来形容我此时此刻的心情,那大概就是哀莫大过于心死吧。我想过一万种我和他分开的原因,但从未想过是他想去做...
    周东琪阅读 470评论 0 0
  • 有一天,当我急匆匆地走上深夜11点的天桥,地铁从天桥前方的轨道上哐当哐当地疾驰而去,而我的目光瞥到灯火辉煌的街道,...
    晏耀飞阅读 333评论 0 1
  • 幸福不在远方,幸福就在你的身边,在日日生活的地方,要有一颗懂得体验点滴美好的心,才会看到散落在日常当中的幸福。幸福...
    兰漫雪阅读 584评论 0 0