#include<stdio.h>///选择链表的原因:方便插入和删除
#include<stdlib.h>///exit函数的声明在这个头文件里
typedef struct Node
{
int coefficient; //系数
int exponent; //指数
struct Node *next; ///该结构体类型的指针
} Node; ///该Node是struct Node的别名,可有可无用于简化命名
typedef Node* LinkList;///LinkList是Node*的别称
void initList(LinkList *head)///初始化链表:接受一个指向链表头指针的指针
{///动态内存分配
if ((*head = (LinkList)malloc(sizeof(Node))) == NULL)
exit(-1);///内存分配失败,函数终止程序
(*head)->next = NULL; ///初始化头节点:指针域赋空,数据域不设置
}
void creatList(LinkList head)///在只有头节点的情况下,定义并创建一个新的结点指针,通过输入不断壮大原只有头节点的列表
{
LinkList p, tail = head; ///tail被初始化为头节点,p
int count;
scanf("%d", &count);
while (count > 0)
{
p = (LinkList)malloc(sizeof(Node));///将malloc返回的void*类型的指针 转换为LinkList类型
if(p==NULL)exit(-1);
scanf("%d%d", &p->coefficient, &p->exponent);
tail->next = p; ///插入节点p至tail后面
tail = p; ///更新tail:向后移动,便于下一次插入
count--;
}
tail->next = NULL;///循环结束,最后一个节点设置为NULL,表示链表的结束
}
void printList(LinkList head)
{ if(head==NULL)exit(-1); ///exit()函数:立即终止程序的运行,返回状态值(0表示成功,非0表示异常)
LinkList p = head->next; ///初始化指针p,指向链表第一个实际的数据点
while (p)///p==NULL标志着链表到达结尾
{
if (p == head->next) ///检查p是否仍指向第一个数据节点
printf("%d %d", p->coefficient, p->exponent);
else ///不是第一个元素,打印的时候前面加一个空格
printf(" %d %d", p->coefficient, p->exponent);
p = p->next; ///节点的移动
}
}
///已完成链表的创建初始化,读入节点数据信息,设置输出格式的操作
void multiplication(LinkList list1, LinkList list2)
{
LinkList result, p = list1->next, q , tail, newNode;
initList(&result);///初始化链表(使存在)
tail = result; ///指向头节点
while (p)///直接调用判断是否为空,所以初始化为链表的第一个有效节点
{///关键点:在循环外初始化p,循环内初始化q,使p节点不变,遍历q链表的每一个节点
///难点:指数保持递减,合并同类项
q = list2->next;///第一个有效节点
while (q)///遍历
{
// 创建“新建的”newNode存储p,q组合后得到的新节点
newNode = (LinkList)malloc(sizeof(Node));
newNode->coefficient = p->coefficient * q->coefficient;///运算法则
newNode->exponent = p->exponent + q->exponent;
newNode->next = NULL; ///封底
LinkList temp = result; ///在result链表中查找应该插入newNode的位置
while (temp->next && newNode->exponent < temp->next->exponent)
{///temp下一个节点非空(temmp不是链表的最后一个元素)、temp第一个"有效元素"大于插入节点,后移遍历
temp = temp->next;///后移
}
// 插入或者合并同类项
if (temp->next == NULL || newNode->exponent > temp->next->exponent)///可以直接将新节点插入的两条件:1.已经遍历完,插到尾部。2.插入节点大于temp中的被遍历到的节点,可以直接插入
{ ///链表插入节点,从后往前避免信息更换错乱
newNode->next = temp->next;
temp->next = newNode;
}
else if (newNode->exponent == temp->next->exponent)
{ ///合并同类项
temp->next->coefficient += newNode->coefficient;
// 如果合并同类项后系数为0,得删除这个节点
if(temp->next->coefficient==0)
{///删除节点
LinkList deleteNode=temp->next; ///使删除的节点还可以被找回(保存指针)
temp->next=deleteNode->next; ///删除节点的方法:我的后面=我后面的后面
free(deleteNode); ///节点被移除后释放内存(不能再被找回)
}
free(newNode); ///删除节点并释放内存(该节点信息已经被合并利用,节点不需要了)
}
q = q->next;///下一个
}
p = p->next;///下一个
}
if (result->next==NULL)///结果链表为空(全都抵消)
{
free(result); ///释放头节点内存
printf("0 0");
}
else ///链表不为空,打印结果链表
{
printList(result);
}
}
void addition(LinkList list1, LinkList list2)///旨在两个链表的相加,并打印出结果
{///newNode作为临时变量,是每次迭代中 独立的、新分配的节点,是用于构建链表的一个个独立的节点(再次调用mallloc分配新内存)
LinkList result, p = list1->next, q = list2->next, tail, newNode; ///result(相加后的链表),p,q(分别跳过头节点,指向两链表的有效节点),tail(追踪至链表的尾部),newNode(临时存储新创建的节点)
initList(&result); ///初始化链表(分配内存,设置头节点,数据域为空)
tail = result; /// 设置为头节点,便于后续添加新节点(移动)
while (p && q) ///两个链表有一个遍历完,就结束
{
newNode = (LinkList)malloc(sizeof(Node));
// 当p的指数大于q的指数,将节点p复制给newNode,将newNode移动到result的末尾,p往后移动,q不动
if (p->exponent > q->exponent)///两链表内指数是递减顺序输入的,输出顺序也是指数递减
{
newNode->coefficient = p->coefficient;
newNode->exponent = p->exponent;
newNode->next = NULL; ///将该链表封底,
tail->next = newNode; ///将得到的结果项 连接到result后面
tail = newNode; ///更新指针(后移)
p = p->next; ///p指数大,直接存p该项,p往下遍历,下一项再与q该项比较
}
else if (p->exponent < q->exponent)
{
// 当p的指数小于q的指数,将节点q复制给newNode,将newNode移动到result的末尾,q往后移动,p不动
newNode->coefficient = q->coefficient;
newNode->exponent = q->exponent;
newNode->next = NULL;
tail->next = newNode;
tail = newNode;
q = q->next;
}
else // 指数相等,系数相加。如果相加后的系数为0,则将p,q直接移动到下一位
{
if (p->coefficient + q->coefficient == 0)
{
p = p->next; ///相同指数,系数互为相反数,相加后该项消失,两链表直接后移
q = q->next;
free(newNode); ///newNode没有被链接到结果链表,则释放分配给他的内存
}
else
{
newNode->coefficient = p->coefficient + q->coefficient;
newNode->exponent = p->exponent;
newNode->next = NULL;
tail->next = newNode;
tail = newNode;
p = p->next; ///两链表都后移
q = q->next;
}
}
}
// 如果p或q还有剩余节点,直接接到result的末尾
if (p==NULL)
{
tail->next = q;
}
if (q==NULL)
{
tail->next = p;
}
if (result->next==NULL)///两链表相加后各项系数都为0,只包含头节点,没有有效节点
{
free(result); ///释放内存(有malloc就要有free)
printf("0 0");
}
else ///相加结束后,result链表有有效节点,打印
{
printList(result);
}
}
int main()
{
LinkList list1, list2;
initList(&list1); ///初始化两个链表(加取地址符,可更改源文件的内容)
initList(&list2);
creatList(list1); ///创建两个信息读入完整的链表
creatList(list2);
multiplication(list1, list2); ///一元多项式的乘法
printf("\n");
addition(list1, list2); ///一元多项式的加法
return 0;
}