线性表
1.6 案例分析与实现
1.6.1 多项式运算
使用数组 p
表示:数组中每个分量 p[i]
表示多项式每项的系数 p
,数组分量的下标 i
即对应每项的指数。如下图:
然后把两个数组对应的分量项相加即可。实现代码参考如下:
// 计算两个多项式相关系数的和,返回结果的系数数组
// pa和pb分别为两个多项式的系数数组
// size_a和size_b分别为两个多项式的系数数组长度
// 返回值为结果多项式的系数数组
int *add_polynomials(int *pa, int *pb, int size_a, int size_b)
{
// 结果多项式的系数数组长度
size_t size_c = size_a > size_b ? size_a : size_b;
// 分配内存空间给结果多项式的系数数组
int *pc = (int *)malloc(size_c * sizeof(int));
if (pc == NULL)
{
printf("Memory allocation failed\n");
return NULL;
}
// 初始化结果多项式的系数为0
for (int i = 0; i < size_c; i++)
{
pc[i] = 0;
}
// 将pa和pb的系数相加到pc中
for (int i = 0; i < size_a; i++)
{
pc[i] += pa[i];
}
for (int i = 0; i < size_b; i++)
{
pc[i] += pb[i];
}
return pc;
}
一个示例:
// 定义多项式pa的系数分别为10, 5, -4, 3, 2
int pa[] = {10, 5, -4, 3, 2};
// 定义多项式pb的系数分别为-3, 8, 4, 0, -5, 7, 2
int pb[] = {-3, 8, 4, 0, -5, 7, 2};
size_t size_a = sizeof(pa) / sizeof(pa[0]); // 计算多项式pa的系数数组长度
size_t size_b = sizeof(pb) / sizeof(pb[0]); // 计算多项式pb的系数数组长度
printf("size_a=%d, size_b=%d\n", size_a, size_b); // 打印多项式的系数数组长度
int *pc = add_polynomials(pa, pb, size_a, size_b);
if (pc == NULL)
{
printf("Failed to add polynomials\n");
return 1; // 如果内存分配失败,返回错误
}
size_t size_c = size_a > size_b ? size_a : size_b; // size_c为结果多项式的系数数组长度
printf("size_c=%d\n", size_c); // 打印结果多项式的系数数组长度
// 打印结果多项式的系数
for (int i = 0; i < size_c; i++)
printf("%d ", pc[i]);
运行程序,打印的内容如下:
size_a=5, size_b=7
size_c=7
7 13 0 3 -3 7 2
时间复杂度取决于较长的多项式,为 O(n)
。
1.6.2 稀疏多项式运算
如果要给多项式是稀疏多项式,那么用顺序表实现比较浪费空间,此时可以考虑使用链表实现。
【算法步骤】
思路和数据结构如下图:
【代码实现】
核心算法实现起来并不难理解,但是在前期要初始化两个相加的多项式,还是比较麻烦些。
1)初始化多项式结点的结构,这个参考视频教程即可。
// 定义多项式节点结构体
// PNode结构体表示多项式的一个节点
// 包含系数、指数和指向下一个节点的指针
typedef struct PNode
{
int coef; // 系数
int expn; // 指数
struct PNode *next; // 指向下一个节点的指针
} PNode, *Polynomial;
2)要按照书上的多项式进行初始化,需要用户输入多项式的数据,有点麻烦,于是考虑封装一个方法进行批量处理。
// 尾插法创建多项式链表
Status createPolynomialTail(Polynomial *polynomia, PNode nodes[], int n)
{
*polynomia = (Polynomial)malloc(sizeof(PNode)); // 创建头结点
if (*polynomia == NULL)
{
return OVERFLOW;
}
(*polynomia)->next = NULL; // 初始化头结点的next指针为NULL
// 创建尾结点,一开始尾结点指向头节点。
PNode *tailNode;
tailNode = *polynomia;
PNode *newNode; // 新结点指针
for (int i = 1; i <= n; i++)
{
newNode = (PNode *)malloc(sizeof(PNode)); // 创建新结点
if (newNode == NULL)
{
return OVERFLOW;
}
newNode->coef = nodes[i - 1].coef; // 设置新结点的数据
newNode->expn = nodes[i - 1].expn; // 设置新结点的指数
newNode->next = NULL; // 将新结点的next指针设置为NULL
tailNode->next = newNode; // 将当前尾结点的next指针指向新结点
tailNode = newNode; // 更新尾结点为新结点
}
return OK;
}
在使用方面就比较容易了,初始化多项式就可以通过如下方式进行:
/* 1. 创建多项式链表1 */
Polynomial p1;
PNode nodes1[] = {
{7, 0, NULL}, // 第一个节点,系数为7,指数为0
{3, 1, NULL}, // 第二个节点,系数为3,指数为1
{9, 8, NULL}, // 第三个节点,系数为9,指数为8
{5, 17, NULL}, // 第四个节点,系数为5,指数为17
};
createPolynomialTail(&p1, nodes1, sizeof(nodes1) / sizeof(nodes1[0]));
PrintList(&p1);
3)实现两个多项式相加。
// 两个多项式的各个系数相加
int addPolynomials(Polynomial *p1, Polynomial *p2, Polynomial *p3)
{
// 初始化结果多项式链表
*p3 = (Polynomial)malloc(sizeof(PNode));
(*p3)->next = NULL; // 初始化结果链表的头结点
PNode *tailNode = *p3; // 尾结点指针,初始指向结果链表的头结点
PNode *current1 = (*p1)->next; // p1的当前结点
PNode *current2 = (*p2)->next; // p2的当前结点
while (current1 != NULL && current2 != NULL)
{
PNode *newNode = (PNode *)malloc(sizeof(PNode)); // 创建新结点
if (current1->expn < current2->expn) // p1的指数小于p2的指数
{
newNode->coef = current1->coef; // 直接复制p1的系数
newNode->expn = current1->expn; // 直接复制p1的指数
current1 = current1->next; // 移动到p1的下一个结点
}
else if (current1->expn > current2->expn) // p1的指数大于p2的指数
{
newNode->coef = current2->coef; // 直接复制p2的系数
newNode->expn = current2->expn; // 直接复制p2的指数
current2 = current2->next; // 移动到p2的下一个结点
}
else // p1和p2的指数相等
{
newNode->coef = current1->coef + current2->coef; // 系数相加
newNode->expn = current1->expn; // 指数相同,直接复制
current1 = current1->next; // 移动到p1的下一个结点
current2 = current2->next; // 移动到p2的下一个结点
}
newNode->next = NULL; // 新结点的next指针设置为NULL
tailNode->next = newNode; // 将当前尾结点指向新结点
tailNode = newNode; // 更新尾结点为新结点
}
// 处理剩余的p1或p2结点
while (current1 != NULL) // 如果p1还有剩余结点
{
PNode *newNode = (PNode *)malloc(sizeof(PNode)); // 创建新结点
newNode->coef = current1->coef; // 复制p1的系数
newNode->expn = current1->expn; // 复制p1的指数
newNode->next = NULL; // 新结点的next指针设置为NULL
tailNode->next = newNode; // 将当前尾结点指向新结点
tailNode = newNode; // 更新尾结点为新结点
current1 = current1->next; // 移动到p1的下一个结点
}
while (current2 != NULL) // 如果p2还有剩余结点
{
PNode *newNode = (PNode *)malloc(sizeof(PNode)); // 创建新结点
newNode->coef = current2->coef; // 复制p2的系数
newNode->expn = current2->expn; // 复制p2的指数
newNode->next = NULL; // 新结点的next指针设置为NULL
tailNode->next = newNode; // 将当前尾结点指向新结点
tailNode = newNode; // 更新尾结点为新结点
current2 = current2->next; // 移动到p2的下一个结点
}
return OK; // 返回成功状态
}
和书上不同,这里构造了一个新的链表进行存储结果,不在原有的基础上处理。因为在有一些场景下,可能原有的多项式还需要使用。
【算法分析】
假设两个多项式的项数分别为 m 和 n,该算法的时间复杂度为 O(m + n),空间复杂度方面书中的方法是为O(1),这里我写的方法需要一个新的链表,空间复杂度最差为 O(m+n)。
1.6.3 图书信息管理
略