一 概述
多项式加法是链表的一个应用,其中核心的难点是判断指数不一样时候的处理,昨天也认真地看了群里面地讨论,老师的那种写法确实存在样例通过的侥幸,然后我选择果断抛弃老师的代码(不是),从自己的理解出发写了Add的核心函数。
先从宏观里理解以下Add中存在的几种情况:
第一种情况
这种情况,只需要把p的指针向后移一位,同时把p的前驱m的指针也想后移动一位,举图上的这个例子,我们可以发现1<4 所以只需要在q保持不变的情况下,去匹配在p中有没有同样指数为4的元素即可。
第二种情况
第二种情况,出现这种情况的前提,一定是目前q指针的指数,在p指针以及p指针的前驱之间的一个值,如果和p指针前驱相同,早就在上一次迭代的时候就已经计算过了,在Case2中,我们可以将其类比为链表的一个插入,关键在于处理好p和m的Next,同时对n做一个free。
第三种情况
这种情况,一定要放在第三种,只有处理完特殊,再来处理一般。p指针指向的元素和q指针指向元素的指数相同,可以相加,但是这里要有一些细节,比如相加的结果为0,需要将这一项free同时,m的next指向p的next皆可。
二 代码展示
2.1 结构体&宏定义
#define OK 1
#define ERROR 0
typedef struct LinkNote
{
struct LinkNote *Next;
int cofficient;
int exponent;
} * LinkList, *LinkNotePtr, LinkNote;
2.2 核心Add函数
void add(LinkNotePtr my_List_1, LinkNotePtr my_List_2)
{
LinkNotePtr p, q, r, m, n;
p = my_List_1->Next;
q = my_List_2->Next;
m = my_List_1, n = my_List_2;
/*******************************/
while ((p != NULL) && (q != NULL))
{
/*******************************/
if (p->exponent < q->exponent)
{
printf("Case 1\n");
m = m->Next; /*前驱同时后移*/
p = p->Next;
}
/*******************************/
else if (p->exponent > q->exponent)
{
printf("Case 2\n");
r = (LinkNotePtr)malloc(sizeof(LinkNote));
r->cofficient = q->cofficient;
r->exponent = q->exponent;
r->Next = p;
m->Next = r;
m = r;
n = q;
q = q->Next;
free(n);
}
/*******************************/
else
{
printf("Case 3\n");
p->cofficient = p->cofficient + q->cofficient;
if (p->cofficient == 0)
{
printf("Case 3.1 相等\n");
m->Next = p->Next;
n = p;
p = p->Next;
free(n);
}
/*******************************/
else
{
printf("Case 3.2 不相等\n");
m = m->Next;
p = p->Next;
}
n = q;
q = q->Next;
free(n);
}
}
/*******************************/
if (p == NULL)
{
m->Next = q;
}
}
至于打印函数,一位Create函数、尾插函数,和单链表的非常相似,这里就不再赘述了,忽略次要条件,突出核心问题。
2.3 测试结果
三 总结&反思
重写ADD函数的过程中遇到了很多问题,最突出的是case1,case2,case3这三种情况的顺序排列问题。这让我想起了去年期末考试,使用数组解决约瑟夫环的那个体。同样是while循环,在while循环内部,优先对谁进行处理是非常关键的,比如在这个例子中,优先处理Case1之后,可能还会进入到Case3中。哈哈哈,我觉有时候我们思考问题时并行的,会觉得很简单,但程序时串行的,这就总会产生一些乌龙,以及考虑不周的地方。