多项式ADT的初阶链表实现(添项、相加、相乘)

本文主要供初学者参考借鉴,欢迎大家一起讨论学习。

描述语言:C语言

抽象数据类型:

以下对于抽象数据类型一元多项式的定义参考清华《数据结构》教材。

读者可以以此为参考,本人在具体实现中加入了自己的风格,且主要是实现了递减特性和添项、相加、相乘的功能。

ADT Polynomical {
    数据对象:D = {ai属于Termset, i = 1,2,...,m, m>=0
            Termset中的每个元素包含一个表示系数的整数和表示指数的整数}
    数据关系:R1 = {<ai-1,ai>|ai-1,ai属于D,且ai-1中的指数值 > ai中的指数值,i=2,...,n}
    基本操作:
        CreatPolyn(&P,m)
      操作结果:输入m项的系数和指数,建立一元多项式P
        DestoryPolyn(&P)
      初始条件:一元多项式P已存在
      操作结果:销毁一元多项式P
        PrintPolyn(P)
      初始条件:一元多项式P已存在
      操作结果:打印一元多项式P    
        PolynLength(P)
      初始条件:一元多项式P已存在
      操作结果:返回一元多项式P中项数
        AddPolyn(&Pa,&Pb)
      初始条件:一元多项式Pa和Pb已存在
      操作结果:完成多项式相加
        SubtractPolyn(&Pa,&Pb)
      初始条件:一元多项式Pa和Pb已存在
      操作结果:完成多项式相减
        MultiplyPolyn(&Pa,&Pb)
      初始条件:一元多项式Pa和Pb已存在
      操作结果:完成多项式相乘
}ADT Polynomical

多项式链表的表示:

typedef struct _polynomical {
    int coe;//系数 coefficient
    int expo;//指数 exponent
    struct _polynomical *next;//切记 struct
    struct _polynomical *prev;//切记 struct
} polynomical;
typedef struct _poly {
    unsigned size;//项数
    polynomical *head;
    polynomical *tail;
} Poly;

*注:此表示方法以便于程序扩展与完善为目的进行设计。

1、将头指针放在一个结构内:相较于给函数传二级指针(ElemType**head)的方法更方便。并且此结构可以包含链表的其他信息,便于程序扩展(如添加尾指针tail,链表长度size)

2、本人还在节点(结点)的结构中加了指向直接前驱元素的指针域,即为双向链表,但在之后暂时没用上,供读者发挥(删除也无妨)

建立接口(函数):

//初始化多项式
Poly poly_creat(void);

//向已有多项式添加项
void poly_add(Poly *pPoly);

//显示多项式
void poly_print(const Poly *pPoly);

//清空多项式
void poly_free(Poly *pPoly);

//多项式相加
Poly poly_combine(Poly *pPoly1, Poly *pPoly2);

//多项式相乘
Poly poly_multiply(Poly *pPoly1, Poly *pPoly2);

此段代码加入了我本人的一些风格,仅供参考讨论,以下为详细分析

实现接口:

之前的“多项式链表的表示”和“建立接口(函数)”可放在一个头文件"polynomical.h"内。

以下为“polynomical.c”中内容:

1、初始化多项式

常规操作

Poly poly_creat(void){
    Poly temp;
    
    temp.size = 0;
    temp.head = NULL;
    temp.tail = NULL;
    
    return temp;
}

2、向已有多项式添加项

本人为多项式链表添加了按指数递减的排列特点。

关键1:合并同类项(不要忽略对size的处理)

关键2:将新的项放在原链表合适位置(确保按指数递减排列)

(此代码有部分重复内容,可以进一步优化)

void poly_add(Poly *pPoly){
    polynomical *poly_temp;
    bool isFound = false;
    
    //创建新的项
    poly_temp = (polynomical *) malloc (sizeof(polynomical));
    printf("Enter the coefficient:\n");
    scanf("%d", &poly_temp->coe);
    //若系数为 0,直接退出
    if (poly_temp->coe == 0) {
        printf("This item is already 0!\n");
        return;
    }
    printf("Enter the exponent:\n");
    scanf("%d", &poly_temp->expo);
    poly_temp->next = NULL;
    poly_temp->prev = NULL;
    
    //链接到多项式
    if (pPoly->size) {
        polynomical *this;
        //查找并合并同类项
        for (this = pPoly->head; this; this = this->next) {
            if (this->expo == poly_temp->expo) {
                this->coe += poly_temp->coe;
                isFound = true;
                break;
            }
        }
        //没有同类项则插入在合适位置
        if (!isFound) {
            polynomical *insert;//将会指向待插入项的后一项
            // for 循环确定 insert 位置
            for (insert = pPoly->head; insert && insert->expo > poly_temp->expo; insert = insert->next);
            // 将 poly_temp 放在 insert 和 insert 前一项之间
            // 注意 insert 为 NULL 的情况
            // 注意插入到第一项的情况
            if (insert && insert->prev == NULL) {//若插入到第一项
                pPoly->head = poly_temp;
                insert->prev = poly_temp;
                poly_temp->next = insert;
                poly_temp->prev = NULL;
            }else if (insert) {
                polynomical *node_temp;
                node_temp = insert->prev;
                insert->prev = poly_temp;
                poly_temp->next = insert;
                poly_temp->prev = node_temp;
                node_temp->next = poly_temp;
            }else{// insert 为 NULL 时直接添加在尾部
                pPoly->tail->next = poly_temp;
                poly_temp->prev = pPoly->tail;
                pPoly->tail = poly_temp;
            }
        }
    }else{
        pPoly->head = poly_temp;
        pPoly->tail = poly_temp;
    }
    //注意合并同类项后不要加 size
    if (!isFound)
        pPoly->size ++;
}

3、显示(打印)多项式

本人考虑了一点显示的美观:

显示方式:

 代码:

void poly_print(const Poly *pPoly){
    polynomical *this = pPoly->head;
    
    if (!this) {
        printf("The poly is 0.\n");
        return;
    }
    for (; this; this = this->next) {
        printf("%dx^(%d)", this->coe, this->expo);
        //注意 this -> next 为 NULL 的情况
        if (this->next && this->next->coe > 0) {
            printf("+");
        }
    }
    putchar('\n');
}

4、清空多项式

常规操作:依次free

void poly_free(Poly *pPoly){
    polynomical *cur, *nex;
    
    for (cur = pPoly->head; cur; cur = nex) {
        nex = cur->next;
        free(cur);
    }
}

5、多项式相加

在相加和相乘功能的实现上,本人与清华《数据结构》上的处理稍有不同。

清华《数据结构》:Pa = Pa + Pb,在原多项式上进行修改,销毁Pb。返回void

本人:Pc = Pa + Pb,保留Pa与Pb,新建Pc。返回Poly

但归并算法的思路差不多:

1)两个指针分别指向两个多项式

2)第一个while同时考虑两个多项式:每次从两个多项式中选出合适的项(符合递减特性)添加到新多项式中,直到其中一个多项式的项遍历完为止。

3)处理另一个多项式中剩余的项

!!!注意:

1)合并同类项(size的处理不可疏忽)

2)此代码仍有优化空间(类似的地方本人直接采取了拷贝【擦汗】)

Poly poly_combine(Poly *pPoly1, Poly *pPoly2){
    //创建新多项式存储多项式的和
    //!!!切记初始化
    Poly res = poly_creat();
    polynomical *this1 = pPoly1->head, *this2 = pPoly2->head;
    polynomical *temp;
    
    while (this1 && this2) {
        if (this1->expo > this2->expo) {
            //新建一个节点并拷贝需要的结构
            temp = (polynomical *) malloc (sizeof(polynomical));
            temp->expo = this1->expo;
            temp->coe = this1->coe;
            temp->next = NULL;
            temp->prev = NULL;
            //链接
            if (res.head) {
                temp->prev = res.tail;
                res.tail->next = temp;
                res.tail = temp;
            }else{
                res.head = temp;
                res.tail = temp;
            }
            this1 = this1->next;
        }else if (this1->expo < this2->expo) {
            //操作同上
            temp = (polynomical *) malloc (sizeof(polynomical));
            temp->expo = this2->expo;
            temp->coe = this2->coe;
            temp->next = NULL;
            temp->prev = NULL;
            if (res.head) {
                temp->prev = res.tail;
                res.tail->next = temp;
                res.tail = temp;
            }else{
                res.head = temp;
                res.tail = temp;
            }
            this2 = this2->next;
        }else {
            temp = (polynomical *) malloc (sizeof(polynomical));
            *temp = *this1;
            //指数不要相加
            temp->coe += this2->coe;
            temp->next = NULL;
            temp->prev = NULL;
            if (res.head) {
                temp->prev = res.tail;
                res.tail->next = temp;
                res.tail = temp;
            }else{
                res.head = temp;
                res.tail = temp;
            }
            this1 = this1->next; this2 = this2->next;
        }
        res.size++;
    }
    //处理 pPoly1 尾部数据
    while (this1) {
        temp = (polynomical *) malloc (sizeof(polynomical));
        *temp = *this1;
        temp->next = NULL;
        temp->prev = NULL;
        if (res.head) {
            temp->prev = res.tail;
            res.tail->next = temp;
            res.tail = temp;
        }else{
            res.head = temp;
            res.tail = temp;
        }
        this1 = this1->next;
        res.size++;
    }
    //处理 pPoly2 尾部数据
    while (this2) {
        temp = (polynomical *) malloc (sizeof(polynomical));
        *temp = *this2;
        temp->next = NULL;
        temp->prev = NULL;
        if (res.head) {
            temp->prev = res.tail;
            res.tail->next = temp;
            res.tail = temp;
        }else{
            res.head = temp;
            res.tail = temp;
        }
        this2 = this2->next;
        res.size++;
    }
    
    return res;
}

6、多项式相乘

可以将两个多项式相乘转化为一系列多项式相加:

M(x) = A(x) * B(x) = A(x) * [b_{1}x^{e_{1}}+b_{2}x^{e_{2}}+...+b_{n}x^{e_{n}}] =\sum_{i=1}^{n}A(x)b_{i}x^{e_{i}}

//多项式相乘:
//分解为一系列加法运算
Poly poly_multiply(Poly *pPoly1, Poly *pPoly2){
    Poly res = poly_creat();
    polynomical *this1 = pPoly1->head, *this2 = pPoly2->head;
    polynomical *temp;
    
    if (!this1 || !this2) {
        return res;
    }
    while (this2) {
        Poly trans = poly_creat();
        //将 A 中每一项依次乘以 B 中某一项
        while (this1) {
            //将每对相乘后存入 temp
            temp = (polynomical *) malloc (sizeof(polynomical));
            temp->coe = this1->coe * this2->coe;
            temp->expo = this1->expo + this2->expo;
            temp->prev = NULL;
            temp->next = NULL;
            //链接到 trans
            if (trans.head) {
                temp->prev = trans.tail;
                trans.tail->next = temp;
                trans.tail = temp;
            }else{
                trans.head = temp;
                trans.tail = temp;
            }
            this1 = this1->next;
        }
        //每次完成后重置 this1
        this1 = pPoly1->head;
        //递增 this2
        this2 = this2->next;
        //更新结果
        res = poly_combine(&res, &trans);
        // trans 归零
        poly_free(&trans);
    }
    
    return res;
}

main()中测试

#include <stdio.h>
#include <stdlib.h>
#include "polynomical.h"

void clearEnter(void);

void choice_list(void);

int main(int argc, char *argv[]){
    Poly poly1 = poly_creat();
    Poly poly2 = poly_creat();
    Poly poly3 = poly_creat();
    Poly poly4 = poly_creat();
    char choice = 'y';
    
    //创建两个多项式
    printf("NOW >>>>> poly1:\n");
    do{
        poly_add(&poly1);
        clearEnter();
        printf("Continue?(y or n)\n");
        scanf("%c", &choice);
    } while (choice != 'n');
    printf("The poly1:\n");
    poly_print(&poly1);
    printf("The size of the poly1: %u\n", poly1.size);
    
    printf("NOW >>>>> poly2:\n");
    do{
        poly_add(&poly2);
        clearEnter();
        printf("Continue?(y or n)\n");
        scanf("%c", &choice);
    } while (choice != 'n');
    printf("The poly2:\n");
    poly_print(&poly2);
    printf("The size of the poly2: %u\n", poly2.size);
    
    clearEnter();
    printf("What do you want to do with this two poly?\n");
    choice_list();
    char selection;
    scanf("%c", &selection);
    
    switch (selection) {
        case 'a':
            //多项式相加
            poly3 = poly_combine(&poly1, &poly2);
            printf("The sum of poly1 & poly2:\n");
            poly_print(&poly3);
            printf("The size of the poly: %u\n", poly3.size);
            break;
        case 'b':
            //多项式相乘
            poly4 = poly_multiply(&poly1, &poly2);
            printf("The product of poly1 & poly2:\n");
            poly_print(&poly4);
            printf("The size of the poly: %u\n", poly4.size);
            break;
        default:
            printf("No matched selection.\n");
            break;
    }
    
    poly_free(&poly1);
    poly_free(&poly2);
    poly_free(&poly3);
    poly_free(&poly4);
    
    return 0;
}

inline
void clearEnter(void){//清空缓冲区
    while (getchar() != '\n') {
        continue;
    }
}

void choice_list(void){
    printf("(a) get sum\t\t"); printf("(b) get product\n");
}

测试结果:

求和:

f(x_{1})=3x^{2}-5x^{4}+2x^{}; f(x_{2})=x^{}-6x^{2}

预期结果:

f(x)=-5x^{4}-3x^{2}+3x^{}

测试:(太长一张图放不下)

 

 结果正确

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值