目录
链表实现两个多项式相加减介绍:
链表是一种常用的数据结构,多项式相加减是线性代数中的常见操作,可以利用链表来实现。
假设有两个多项式P(x)和Q(x),它们分别为:
P(x) = a0 + a1x + a2x^2 + ... + anxn
Q(x) = b0 + b1x + b2x^2 + ... + bmxm
其中a0, a1, ..., an和b0, b1, ..., bm是多项式P(x)和Q(x)的系数,n和m是它们的次数。
我们可以使用链表来表示这两个多项式。链表中每个节点表示多项式中的一项,包含两个属性:系数和次数。因此,可以定义一个多项式节点结构体:
struct PolyNode {
int coef; // 系数
int exp; // 次数
struct PolyNode *next;
};
在实现多项式相加减时,需要遍历两个链表,对于同一次数的项进行系数相加减,然后将结果保存到一个新的链表中。可以按照以下步骤实现:
-
遍历链表P和Q,依次将它们的项插入到一个新的链表R中,按照项次从小到大的顺序排列。具体而言,可以从链表P和Q中分别取出一项,比较它们的次数,将次数小的项插入到链表R的尾部。如果它们的次数相同,就将它们的系数相加,并插入到链表R的尾部。
-
遍历链表R,对于同一次数的项,将它们的系数相加减,并删除其中一个项。具体而言,可以从链表R的头部开始,依次比较相邻的两项,如果它们的次数相同,就将它们的系数相加,并删除其中一个项。如果不同,就继续比较下一对相邻的项,直到链表R的尾部。
-
最后得到的链表R即为多项式相加减的结果。
下面是多项式相加减的代码实现:
#include <stdio.h>
#include <stdlib.h>
struct term {
float coe;//系数
float exp;//指数
struct term *next;
};
//内存分匹配函数
struct term* allocate(size_t size) {
struct term* ptr = (struct term*) malloc (size);
if (ptr == NULL) {
fprintf(stderr, "内存分配失败");
exit(EXIT_FAILURE);
}
return ptr;
}
//创建新的多项式项
struct term* createterm (float coe, float exp) {
struct term* newterm = allocate (sizeof (struct term));
newterm->coe = coe;
newterm->exp = exp;
newterm->next = NULL;
return newterm;
}
//再多项式中插入新项,按指数由高到低排序
void insertterm (struct term** head, struct term* newterm) {
if (*head == NULL || (*head)->exp < newterm->exp) {
newterm->next = *head;
*head = newterm;
} else {
struct term* current = *head;
while (current->next != NULL && current->next->exp > newterm->exp) {
current = current->next;
}
newterm->next = current->next;
current->next = newterm;
}
}
//输出多项式
void print (struct term* head) {
struct term* current = head;
while (current != NULL) {
printf("%.2fX^%.2f", current->coe, current->exp);
current = current->next;
if (current != NULL) {
printf(" + ");
}
}
printf("\n");
}
//多项式相加
struct term* add (struct term* p1, struct term* p2) {
struct term* head = NULL;
while (p1 != NULL && p2 != NULL) {
if (p1->exp > p2->exp) {
insertterm(&head, createterm(p1->coe, p1->exp));
p1 = p1->next;
} else if (p1->exp < p2->exp) {
insertterm(&head, createterm(p2->coe, p2->exp));
p2 = p2->next;
} else {
float sum = p1->coe + p2->coe;
if (sum != 0) {
insertterm(&head, createterm(sum, p1->exp));
}
p1 = p1->next;
p2 = p2->next;
}
}
while (p1 != NULL) {
insertterm(&head, createterm(p1->coe, p1->exp));
p1 = p1->next;
}
while (p2 != NULL) {
insertterm(&head, createterm(p2->coe, p2->exp));
p2 = p2->next;
}
return head;
}
void freelist(struct term* head) {
struct term* current = head;
while (current != NULL) {
struct term* temp = current;
current = current->next;
free(temp);
}
}
int main() {
//定义多项式1
struct term* p1 = NULL;
printf("请输入多项式1的项数:");
int n1;
scanf("%d", &n1);
for (int i =0; i < n1; i++) {
float coe, exp;
printf("请输入第%d项的系数和指数(空格分开):",i+1);
scanf("%f %f",&coe, &exp);
insertterm(&p1, createterm(coe,exp));
}
//定义多项式2
struct term* p2 = NULL;
printf("请输入多项式2的项数:");
int n2;
scanf("%d", &n2);
for (int i =0; i < n2; i++) {
float coe, exp;
printf("请输入第%d项的系数和指数(空格分开):",i+1);
scanf("%f %f",&coe, &exp);
insertterm(&p2, createterm(coe,exp));
}
//多项式相加
struct term* result = add(p1,p2);
//输出结果
printf("多项式1:");
print(p1);
printf("多项式2:");
print(p2);
printf("相加结果:");
print(result);
//释放内存
freelist(p1);
freelist(p2);
freelist(result);
}
这个链表实现多项式相加的程序具体实现步骤如下:
-
定义了一个结构体 term,用来表示多项式中的每一项。每一项有系数 coe 和指数 exp,以及一个指向下一项的指针 next。
-
实现了三个函数:allocate、createterm 和 insertterm。
- allocate:用来动态分配内存,当内存分配失败时,会打印错误信息并退出程序。
- createterm:用来创建一个新的多项式项,输入这个项的系数和指数,返回一个指向新项的指针。
- insertterm:用来在多项式中插入新项,按指数由高到低排序。若插入的项指数高于当前链表中最高项的指数,则将该项作为新的头结点。否则遍历链表找到合适的位置进行插入。
-
实现了函数 print,用来输出多项式。
-
实现了函数 add,用来将两个多项式相加。算法实现如下:
- 定义一个空链表 head,用来存储相加结果。
- 循环遍历两个多项式链表 p1 和 p2,对于每个项,分别判断其指数大小。
- 如果 p1 的指数较大,则将其插入 head 中,并将 p1 的指针后移一位。
- 如果 p2 的指数较大,则将其插入 head 中,并将 p2 的指针后移一位。
- 如果 p1 和 p2 的指数相等,则将它们的系数相加。若和不为 0,则将其插入 head 中。同时将 p1 和 p2 的指针后移一位。
- 如果其中一个多项式已经遍历完,但另一个还有项,则将剩余的项依次插入 head 中。
- 返回 head。
- 最后在 main 函数中,通过输入多项式的项数和系数指数,创建两个多项式链表 p1 和 p2,并调用函数 add 进行相加操作。然后依次输出多项式 p1、p2 和相加结果,并释放动态分配的内存。
注意:代码中使用了动态内存分配,需要确保在使用完毕后及时释放内存,防止内存泄漏。
各个函数的详细解释:
allocate(size_t size)函数:
这段代码定义了一个名为allocate
的函数,该函数的功能是动态分配内存并返回一个指向该内存块的指针。这里的struct term*
指的是一个指向struct term
类型的指针。函数的第一个参数是size_t size
,这是一个无符号整数类型的变量,它表示要分配的内存块的字节数。函数体中,首先使用标准库函数malloc()
动态分配了一个大小为size
字节的内存块,然后将其强制转换为指向struct term
类型的指针,并将其赋值给名为ptr
的指针变量。如果内存分配失败,则函数将打印一个错误消息并调用exit()
函数终止程序的执行。最后,函数返回指向分配的内存块的指针。
createterm (float coe, float exp)函数:
这段代码定义了一个函数 createterm
,用于创建一个新的多项式项。该函数接受两个参数:一个是项的系数 coe
,一个是项的指数 exp
。函数返回一个指向新创建的多项式项的指针。在函数内部,首先调用了 allocate
函数分配一段内存用于存储新的多项式项。然后将传入的系数和指数值赋给新项的 coe
和 exp
成员。最后将 next
成员设置为 NULL
,因为这是新项插入到多项式中的最后一项。该函数的设计可以使得创建新的多项式项变得简单和方便,同时还避免了内存分配时可能发生的错误。
insertterm (struct term** head, struct term* newterm)函数:
这段代码实现了一个将新的项(结构体term类型)插入到单链表中的函数,其中参数head是一个指向链表头节点的指针,newterm是需要插入的新项。
该函数的实现逻辑如下:
- 如果链表为空或新项的指数大于链表头节点的指数,则将新项插入到链表头部。
- 否则,遍历链表直到找到一个指数小于等于新项的节点,将新项插入到该节点之后。
这里使用了一个指向指针的指针head,是为了能够在函数内部修改head指针指向的节点(即修改链表头节点)。在函数执行过程中,会不断更新current指针指向的节点,直到找到合适的位置将新项插入链表。最后,将newterm的next指针指向current->next,将current的next指针指向newterm,即完成了新项的插入操作。
print (struct term* head)函数:
这段代码定义了一个打印多项式的函数,函数名为 print
,参数为一个指向多项式的头结点的指针。函数内部通过一个 while 循环遍历多项式的每一项,并打印出每一项的系数和指数。其中,使用 printf
函数以格式化的方式输出系数和指数,系数和指数均保留两位小数。同时,在输出每一项之前,判断当前项是否是最后一项,若不是则在项的末尾输出 "+"。函数执行完毕后,会自动换行输出,以便在多次调用时每个多项式的输出都在新的一行上。
add (struct term* p1, struct term* p2)函数:
这个函数实现了两个多项式的加法,接受两个参数p1和p2,它们都是指向多项式的结构体term的指针。函数返回一个新的指针,指向一个新的多项式,它是p1和p2相加的结果。
首先,函数初始化一个新的链表头指针head,然后通过迭代p1和p2来遍历两个多项式。在每一次迭代中,函数比较p1和p2中当前项的指数大小,如果p1当前项的指数大于p2当前项的指数,则将p1当前项添加到结果多项式中,反之则将p2当前项添加到结果多项式中。如果p1和p2当前项的指数相等,则将它们的系数相加,并将和非零的项添加到结果多项式中。最后,函数处理任何一个多项式中可能剩余的项并将它们添加到结果多项式中。最后,函数返回结果多项式的头指针。
在每个if语句块中,函数调用了insertterm()函数将新项插入到结果多项式中。这个函数的作用是将新项插入到多项式的适当位置,以确保结果多项式保持单调递减的指数顺序。
在每个while循环中,函数通过p1和p2的next指针遍历两个多项式。这样,函数可以一次处理一个项并将它添加到结果多项式中。最后,函数返回结果多项式的头指针head。
freelist(struct term* head)函数:
该函数用于释放链表中的所有结点内存,避免内存泄漏。函数首先将头指针传递进来,并使用一个 current 指针来遍历整个链表,释放链表中每个结点的内存。在 while 循环中,当前结点 current 的内存被释放,并将当前结点的 next 指针保存到一个临时变量 temp 中。然后将 current 指针移动到下一个结点,并使用 free() 函数释放 temp 指向的结点内存。最终,当遍历到链表的末尾,current 指向 NULL 时,函数结束执行。
注意事项:
在链表实现两个多项式相加减需要注意链表的操作必须要考虑多种情况,如链表为空、链表只有一个节点、链表节点顺序不同等等。还有在遍历链表时,需要注意链表节点的顺序,因为相加减时需要按照指数从大到小的顺序依次进行计算。还有在插入节点时,需要注意节点的指数大小关系,可以通过比较当前节点和待插入节点的指数大小,来决定是插入到当前节点的前面还是后面。在计算相加减时,需要考虑系数相加后是否为零,如果为零则不需要插入节点。在实现函数时,需要特别注意内存分配和释放,否则可能会出现内存泄漏或野指针等问题。在处理边界情况时,需要仔细考虑,比如当一个多项式为空时,直接将另一个多项式复制到结果中。还需要仔细检查代码逻辑,确保每个操作都正确无误,尤其是涉及到指针操作时更需要注意。