一、实验目的
掌握顺序表和单链表的存储特点及插入、删除等算法。
二、实验内容及要求
1、任务描述:灵活运用顺序表和单链表的相关算法实现一元多项式的计算。
2、主要数据类型与变量
typedef struct LNode {
int c;
int e;
struct LNode* Next;
}*List;
该结构体数据域用来存储多项式每一项的系数和指数,指针域用来存储下一个项的地址。
3、算法或程序模块
void Insert(List L, int c, int e);//将c和e存入一个结构体后连接在链表L之后 连接前合并指数相同的项,进行有序插入
List Input(); //将输入的系数和指数通过Insert()方法生成结点,连接在定义在该函数中定义的以head为头结点的链表中,并返回该头节点
void Add(List A, List B);//将链表A和B通过加法运算合并到一个新的链表中
void Sub(List A, List B);//将链表A和B通过减法运算合并到一个新的链表中
void Mulit(List A, List B);//将链表A和B通过乘法运算合并到一个新的链表中
void Update(List L);//将链表中系数为0的项除去
void PrintList(List L);//输出链表L
void Init();//初始化
void PrintList_Reverse(List L);//反向输出链表L
该程序主要分为9个模块,主要的算法如下:
void Insert(List L, int c, int e)
{
List node = (List)malloc(sizeof(struct LNode));
node->c = c;
node->e = e;
node->Next = NULL;
List p;
p = L; //L为待连接的链表
while (p->Next)
{
if (p->Next->e == node->e)
{
p->Next->c += node->c;
return;
}
if (p->Next->e > node->e)
{
break;
}
p = p->Next;
}
node->Next = p->Next;
p->Next = node;
}
该函数首先建立一个单独的结点,结点的c,e值为传入的相应的值。之后定义一个指向链表L头节点的指针,通过指针的移动来遍历链表中的每一个结点,如果链表中结点中的e即指数相等,则将新建立的结点的系数与链表中的结点的系数相加;如果新建立的结点的系数小于链表中的结点的系数就结束遍历。最后将新建立的结点插入在对应的位置,即可实现指数相同的项的合并,以及项的有序插入。
List Input()
{
printf("请输入系数和指数,以0 0结束->\n");
List head = (List)malloc(sizeof(struct LNode));
head->Next = NULL;
int c, e;
while (scanf("%d%d", &c, &e), c || e)
{
Insert(head, c, e);
}
return head;
}
该函数将输入的系数和指数通过Insert()方法生成结点,连接在定义在该函数中定义的以head为头结点的链表中,并返回该头节点的地址。
void Add(List A, List B)
{
List head = (List)malloc(sizeof(struct LNode));
head->Next = NULL;
List p;
p = A->Next;
while (p)
{
Insert(head, p->c, p->e);
p = p->Next;
}
p = B->Next;
while (p)
{
Insert(head, p->c, p->e);
p = p->Next;
}
Update(head);
printf("多项式A+B的结果为:\n");
printf("升序:"); PrintList(head);
printf("降序:"); PrintList_Reverse(head);printf("\n");
}
该函数首先创建一个新链的头结点,然后通过分别设置两个指针来遍历链表A和链表B,最后通过Update()函数消除系数为0的项,最后按照升序和降序输出。
void Mulit(List A,List B)
{
List head = (List)malloc(sizeof(struct LNode));
head->Next = NULL;
List p, q;
p = A->Next;
q = B->Next;
if (!p)//p为空
{
printf("多项式A*B的结果为\n");
printf("升序:"); PrintList(head);
printf("降序:"); PrintList_Reverse(head); printf("\n");
return;
}
if (!q)//q为空
{
printf("多项式A*B的结果为\n");
printf("升序:"); PrintList(head);
printf("降序:"); PrintList_Reverse(head); printf("\n");
return;
}
while (p)
{
q = B->Next;
while (q)
{
Insert(head, p->c * q->c, p->e + q->e);
q = q->Next;
}
p = p->Next;
}
Update(head);
printf("多项式A*B的结果为:\n");
printf("升序:"); PrintList(head);
printf("降序:"); PrintList_Reverse(head); printf("\n");
}
该函数遍历A链的所有结点,遍历B链的所有结点,然后将AXB的所有结点添加(insert)到新链中。若出现A链为空或B链为空的情况,直接通过PrintList()函数输出0;若都不为空,则通过双重循环将相乘后的项添加到新链中,最后通过Update()函数消除系数为0的项,最后按照升序和降序输出。
void Update(List L)
{
List p = L;
while (p->Next)
{
if (p->Next->c == 0)
{
p->Next = p->Next->Next;
}
p = p->Next;
}
}
建立指向链表L头结点的指针来遍历链表L,若项的系数为0则删除该项。
void Init()
{
printf("请依次输入A,B多项式:\n");
List A = Input();
List B = Input();
printf("----------------------------------------\n");
printf("A = "); PrintList(A);
printf("B = "); PrintList(B);
printf("\n");
while (1)
{
int flag;
printf("---------------操作命令集---------------\n");
printf("****************************************\n");
printf("* 1.相加A+B *\n");
printf("* 2.相减A-B *\n");
printf("* 3.相减B-A *\n");
printf("* 4.相乘B*A *\n");
printf("* 5.Return *\n");
printf("****************************************\n");
scanf("%d", &flag);
switch (flag)
{
case 1:
Add(A, B);
break;
case 2:
Sub(A, B);
break;
case 3:
Sub(B, A);
break;
case 4:
Mulit(A, B);
break;
case 5:
return;
break;
default:
break;
}
}
}
利用while循环和switch语句将各个函数进行封装,生成系统菜单,实现简单的交互界面。
三、测试
1、方案
测试数据:
1 0 2 2 3 3 0 0
-2 2 3 3 -4 4 0 0
2、结果
点击运行,依次输入两个测试数据:
输入数据以规定的格式进行输出,操作命令集正常显示。
输入1进行加法操作:
多项式加法运算结果正确,且多项式中无重复阶项、无零系数项。升幂和降幂顺序正确。
输入2进行减法操作:
多项式减法运算结果正确,且多项式中无重复阶项、无零系数项。升幂和降幂顺序正确。
输入4进行乘法操作:
多项式乘法运算结果正确,且多项式中无重复阶项、无零系数项。升幂和降幂顺序正确。
输入5正常退出。
四、总结与讨论
通过本次一元多项式计算器的实验我进一步掌握了有关链表的相关操作,例如链表中结点的插入和删除、链表元素的遍历,进一步理解了链式存储的特点。学习了合并链表时两种不同方法的思想,第一种是将其中一条链作为母链,再将另一条链的结点都添加到母链中;第二种是新增一条链,将两条链的所有结点都添加到新链中。掌握了两种动态生成链表的方法,头插法(体现在insert函数)和尾插法(体现在PrintList_Reverse函数),进一步加强了链表中对指针的认识。其次理解了带头结点和无头结点的区别。本次实验虽然花费了很多的时间,但通过实际的编程我对线性表的这部分知识的理解有了很大的提高,认识到了很多细节,之前不借助书很难自己编写出链表和顺序表的相关的算法,现在已经基本能够熟练运用了,同时锻炼了整体的构思能力,总之很值得。
附:程序的源代码
#include
#include
#include
typedef struct LNode {
int c;
int e;
struct LNode* Next;
}*List;
void Insert(List L, int c, int e);//将c和e存入一个结构体后连接在链表L之后 连接前合并指数相同的项,进行有序插入
List Input(); //将输入的系数和指数通过Insert()方法生成结点,连接在定义在该函数中定义的以head为头结点的链表中,并返回该头节点
void Add(List A, List B);//将链表A和B通过加法运算合并到一个新的链表中
void Sub(List A, List B);//将链表A和B通过减法运算合并到一个新的链表中
void Mulit(List A, List B);//将链表A和B通过乘法运算合并到一个新的链表中
void Update(List L);//将链表中系数为0的项除去
void PrintList(List L);//输出链表L
void Init();//初始化
void PrintList_Reverse(List L);//反向输出链表L
int main()
{
Init();
return 0;
}
void Init()
{
printf("请依次输入A,B多项式:\n");
List A = Input();
List B = Input();
printf("----------------------------------------\n");
printf("A = "); PrintList(A);
printf("B = "); PrintList(B);
printf("\n");
while (1)
{
int flag;
printf("---------------操作命令集---------------\n");
printf("****************************************\n");
printf("* 1.相加A+B *\n");
printf("* 2.相减A-B *\n");
printf("* 3.相减B-A *\n");
printf("* 4.相乘B*A *\n");
printf("* 5.Return *\n");
printf("****************************************\n");
scanf("%d", &flag);
switch (flag)
{
case 1:
Add(A, B);
break;
case 2:
Sub(A, B);
break;
case 3:
Sub(B, A);
break;
case 4:
Mulit(A, B);
break;
case 5:
return;
break;
default:
break;
}
}
}
void Insert(List L, int c, int e)
{
List node = (List)malloc(sizeof(struct LNode));
node->c = c;
node->e = e;
node->Next = NULL;
List p;
p = L; //L为待连接的链表
while (p->Next)
{
if (p->Next->e == node->e)
{
p->Next->c += node->c;
return;
}
if (p->Next->e > node->e)
{
break;
}
p = p->Next;
}
node->Next = p->Next;
p->Next = node;
}
List Input()
{
printf("请输入系数和指数,以0 0结束->\n");
List head = (List)malloc(sizeof(struct LNode));
head->Next = NULL;
int c, e;
while (scanf("%d%d", &c, &e), c || e)
{
Insert(head, c, e);
}
return head;
}
void Add(List A, List B)
{
List head = (List)malloc(sizeof(struct LNode));
head->Next = NULL;
List p;
p = A->Next;
while (p)
{
Insert(head, p->c, p->e);
p = p->Next;
}
p = B->Next;
while (p)
{
Insert(head, p->c, p->e);
p = p->Next;
}
Update(head);
printf("多项式A+B的结果为:\n");
printf("升序:"); PrintList(head);
printf("降序:"); PrintList_Reverse(head);printf("\n");
}
void Sub(List A, List B)//将链表A和B合并到一个新的链表中
{
List head = (List)malloc(sizeof(struct LNode));
head->Next = NULL;
List p;
p = A->Next;
while (p)
{
Insert(head, p->c, p->e);
p = p->Next;
}
p = B->Next;
while (p)
{
Insert(head, -p->c, p->e);
p = p->Next;
}
Update(head);
printf("多项式A-B/B-A的结果为\n");
printf("升序:"); PrintList(head);
printf("降序:"); PrintList_Reverse(head); printf("\n");
printf("\n");
}
void Mulit(List A,List B)
{
List head = (List)malloc(sizeof(struct LNode));
head->Next = NULL;
List p, q;
p = A->Next;
q = B->Next;
if (!p)//p为空
{
printf("多项式A*B的结果为\n");
printf("升序:"); PrintList(head);
printf("降序:"); PrintList_Reverse(head); printf("\n");
return;
}
if (!q)//q为空
{
printf("多项式A*B的结果为\n");
printf("升序:"); PrintList(head);
printf("降序:"); PrintList_Reverse(head); printf("\n");
return;
}
while (p)
{
q = B->Next;
while (q)
{
Insert(head, p->c * q->c, p->e + q->e);
q = q->Next;
}
p = p->Next;
}
Update(head);
printf("多项式A*B的结果为:\n");
printf("升序:"); PrintList(head);
printf("降序:"); PrintList_Reverse(head); printf("\n");
}
void Update(List L)
{
List p = L;
while (p->Next)
{
if (p->Next->c == 0)
{
p->Next = p->Next->Next;
}
p = p->Next;
}
}
void PrintList(List L)
{
List p;
p = L->Next;
if (!p)
{
printf("0");
}
while (p)
{
if (p->c > 0 && p != L->Next)
{
printf("+");
}
if (p->e == 0)
{
printf("%d", p->c);
}
else
{
printf("%dx\^%d", p->c, p->e);
}
p = p->Next;
}
printf("\n");
}
void PrintList_Reverse(List L)
{
List rear = (List)malloc(sizeof(struct LNode));
rear->Next = NULL;
List p = L->Next;
while (p)
{
List temp = (List)malloc(sizeof(struct LNode));
temp->Next = NULL;
temp->c = p->c;
temp->e = p->e;
temp->Next = rear->Next;
rear->Next = temp;
p = p->Next;
}
PrintList(rear);
}