一、问题描述

一元n次多项式是代数学中经常出现的代数式,对于一元n次多项式的操作有很重要的实际意义。由于一个一元n次多项式最多有n+1项,且互不相关,所以可以用一个线性表来保存一个多项式,从前至后次数递增。对于一个一元n次多项式,我们可以定义操作:多项式的加法、减法、乘法。

本次小作业采用了链式表示的线性表实现,且只实现了多项式的加法。我认为如果要实现多项式的乘法,顺序表示的线性表更合适。

二、数据结构——线性表

1、链式表示:

链式表示的线性表,每个单位元由数据域和指针域组成,数据域保存当前结点的数值,而指针域保存的是下一个逻辑位置的地址,以便于通过这个指针访问下一个结点。与顺序表示相比,链式表示具有插入、删除灵活方便的特点,然而访问不方便,只能够从头指针处遍历。

2、顺序表示:

顺序表示的线性表,用一段物理存储上连续的空间模拟线性表,以物理上的位置的顺序关系,表示逻辑上的顺序关系。由于其物理地址的相近,所以在访问方便的同时,出现了两个麻烦:一是当一次申请的空间不够时,只能重新申请一段更大的空间,把之前的所有数据按顺序“搬”过去,否则无法保证其物理顺序的连续性;二是当线性表需要插入、删除操作时,需要对一部分数据进行“移位”操作,时间复杂度高。

3、基于本小作业对两种表示的对比分析:

此次作业是要求做两个一元n次多项式的加法,抽象到ADT上来看,就是两个线性表的分项加法,所以不涉及到结点的插入、删除操作,于是链式表示的优势被削弱,而顺序表示的劣势不那么明显了。相比较而言,两者的实现没什么区别,所以我选择了链式表示来实现。

更多地来想,如果需要做多项式的乘法,那么顺序表示就比链式表示的优势要大了。多项式乘法的算法核心可以大致说明为:LC(i+j-1) += LA(i)*LB(j)。这里涉及到寻找i+j-1位置的LC的值并进行修改的操作,如果使用顺序表示更方便找到该位置。

三、算法的设计及实现

(1)建立线性表LA和LB,并读入数据。

(2)将LB中的每一项按顺序逐项加到LA中对应的项。

(3)如果LB比LA长,则把LB中剩余元素按顺序依次加到LA中。

(4)最后得到的LA就是最终结果。

四、预期结果和实验中的问题

1、预期结果:

输入两个一元n次多项式的各项系数后,按照次数递增分别保存在LA和LB中,然后将LB中的每一项对应加在LA中。

如LA={1,2,3,4,5,6}表示fa(x)=1+2*x+3*x^2+4*x^3+5*x^4+6*x^5,LB={2,2,3}表示fb(x)=2+2*x+3*x^2,则得到的结果应该是{3,4,6,4,5,6}表示fa(x)+fb(x)=3+4*x+6*x^2+4*x^3+5*x^4+6*x^5。

2、实验中的问题:

除去线性表实现的一些细节问题以外,还有针对此次小作业的问题。

上面有提到的是,如果要实现多项式的乘法,若使用顺序表示的线性表,则可以直接遍历LA和LB,每一个合法位置执行LC(i+j-1) += LA(i)*LB(j)就可以了;而假如要使用链式表示的线性表来实现,如果继续按照顺序表示的方式来遍历LA和LB,这样处理LC的位置在不停地变动,查找该位置时间开销很大,所以可以选择遍历i+j-1的值,对于一个固定的i+j-1,通过遍历i求出j的值来计算LC(i+j-1)的值。

我也思考了多项式除法的问题,发现涉及到数论的一些结论,类似于高精度数除以高精度数,还没有比较好的处理方式。当然,带余除法是可以用LA一直减去LB直到0<LA<LB为止。

附:c++源代码:

  1 #include <iostream>
2 #include <cstdio>
3
4 using namespace std;
5
6 struct node
7 {
8 int Num;
9 node *next;
10 };
11
12 class MyList
13 {
14 private:
15 int Len;
16 node *pHead;
17
18 public:
19 void InitList()//构造一个空的线性表
20 {
21 Len = 0;
22 pHead = NULL;
23 }
24 void ClearList()//重置为空表
25 {
26 node *Tmp;
27 while(pHead)
28 {
29 Tmp = pHead;
30 pHead = pHead -> next;
31 delete Tmp;
32 }
33 Len = 0;
34 }
35 bool ListEmpty()//判断L是否为空表
36 {
37 return pHead == NULL;
38 }
39 int ListLength()//返回L中数据元素个数
40 {
41 return Len;
42 }
43 bool GetElem(int Pos, int &e)//返回第Pos个元素,出错返回true
44 {
45 if(Pos < 1 || Pos > Len)
46 {
47 printf("Wrong position!\n");
48 return true;
49 }
50 node *Cur = pHead;
51 int Index = 0;
52 while(++Index < Pos && Cur)
53 Cur = Cur -> next;
54 e = Cur -> Num;
55 return false;
56 }
57 //LocateElem(L, e, compare())//返回L中第一个与e满足关系compare()的元素的位序,不存在返回0
58 bool PriorElem(int e, int &Pre_e)//若e是L中的元素,返回e的前躯,失败时返回true
59 {
60 if(pHead -> Num == e)
61 {
62 printf("Cannot find the precursor!\n");
63 return true;
64 }
65 node *Cur = pHead, *Prev;
66 while(Cur)
67 {
68 if(Cur -> Num == e)
69 break;
70 Prev = Cur;
71 Cur = Cur -> next;
72 }
73 if(!Cur)
74 {
75 printf("Cannot find the element!\n");
76 return true;
77 }
78 Pre_e = Prev -> Num;
79 return false;
80 }
81 bool NextElem(int e, int &Next_e)//若e是L中的元素,返回e的后继,错误时返回true
82 {
83 node *Cur = pHead;
84 while(Cur)
85 {
86 if(Cur -> Num == e)
87 break;
88 Cur = Cur -> next;
89 }
90 if(!Cur)
91 {
92 printf("Cannot find the element!\n");
93 return true;
94 }
95 Cur = Cur -> next;
96 if(!Cur)
97 {
98 printf("Cannot find the successor!\n");
99 return true;
100 }
101 Next_e = Cur -> Num;
102 return false;
103 }
104 bool ListInsert(int Pos, int e)//在Pos位置插入元素e,失败时返回true
105 {
106 if(Pos < 1 || Pos > Len + 1)
107 {
108 printf("Wrong position!\n");
109 return true;
110 }
111 node *InsElem = new node;
112 if(Pos == 1)
113 {
114 InsElem -> next = pHead;
115 pHead = InsElem;
116 InsElem -> Num = e;
117 }
118 else
119 {
120 node *Cur = pHead;
121 int Index = 0;
122 while(++Index + 1 < Pos && Cur)
123 Cur = Cur -> next;
124 InsElem -> next = Cur -> next;
125 Cur -> next = InsElem;
126 InsElem -> Num = e;
127 }
128 Len++;
129 return false;
130 }
131 bool ListDelete(int Pos, int &e)//删除Pos位置的元素,用e返回,错误时返回true
132 {
133 if(Pos < 1 || Pos > Len)
134 {
135 printf("Wrong position!\n");
136 return true;
137 }
138 node *DelElem = pHead;
139 if(Pos == 1)
140 {
141 pHead = DelElem -> next;
142 e = DelElem -> Num;
143 delete DelElem;
144 }
145 else
146 {
147 node *Prev;
148 int Index = 0;
149 while(++Index < Pos && DelElem)
150 {
151 Prev = DelElem;
152 DelElem = DelElem -> next;
153 }
154 Prev -> next = DelElem -> next;
155 e = DelElem -> Num;
156 delete DelElem;
157 }
158 Len--;
159 return false;
160 }
161 //ListTraverse(L, visit())//依次对L中的每个数据元素调用函数visit(),一旦visit()失败,则操作失败
162 void PrintList()
163 {
164 if(ListEmpty())
165 {
166 printf("The List is empty!\n");
167 return ;
168 }
169 node *Cur = pHead;
170 int Index = 0;
171 while(++Index < Len && Cur)
172 {
173 printf("%d ",Cur -> Num);
174 Cur = Cur -> next;
175 }
176 printf("%d\n",Cur -> Num);
177 }
178 bool ElemPrio(node a, node b)
179 {
180 return a.Num < b.Num;
181 }
182 bool ChangeElem(int Pos, int El) //把Pos位置元素的值改为El,失败返回true
183 {
184 if(Pos < 1 || Pos > Len)
185 {
186 printf("Wrong position!\n");
187 return true;
188 }
189 node *Cur = pHead;
190 int Index = 0;
191 while(++Index < Pos && Cur)
192 Cur = Cur -> next;
193 Cur -> Num = El;
194 return false;
195 }
196 void MergeList(MyList Lb) //把Lb插入L中
197 {
198 int aElem, bElem, aIndex = 0;
199 while(aIndex < Len && (!Lb.ListEmpty()))
200 {
201 GetElem(++aIndex, aElem);
202 Lb.GetElem(1, bElem);
203 if(aElem > bElem)
204 {
205 Lb.ListDelete(1, bElem);
206 ListInsert(aIndex, bElem);
207 }
208 }
209 while(!Lb.ListEmpty())
210 {
211 Lb.ListDelete(1, bElem);
212 ListInsert(Len + 1, bElem);
213 }
214 }
215 void AddList(MyList Lb) //按项加法,把Lb往L中加
216 {
217 if(Lb.ListEmpty())
218 return ;
219 int bElem;
220 node *Cur = pHead;
221 while(Cur && (!Lb.ListEmpty()))
222 {
223 Lb.ListDelete(1, bElem);
224 Cur -> Num += bElem;
225 Cur = Cur -> next;
226 }
227 while(!Lb.ListEmpty())
228 {
229 Lb.ListDelete(1, bElem);
230 ListInsert(Len, bElem);
231 }
232 }
233 void PrintList_ForPolynomial()
234 {
235 if(ListEmpty())
236 {
237 printf("There is something wrong!\n");
238 return ;
239 }
240 node *Cur = pHead;
241 int Index = 0;
242 while(++Index < Len && Cur)
243 {
244 if(Index == 1)
245 printf("%d + ", Cur -> Num);
246 else if(Index == 2)
247 printf("%d * x + ", Cur -> Num);
248 else
249 printf("%d * x^%d + ", Cur -> Num, Index - 1);
250 Cur = Cur -> next;
251 }
252 if(Index == 1)
253 printf("%d\n", Cur -> Num);
254 else if(Index == 2)
255 printf("%d * x\n", Cur -> Num);
256 else
257 printf("%d * x^%d\n", Cur -> Num, Index - 1);
258 }
259 };
260
261 void Read(MyList &L)
262 {
263 int n, i, Elem;
264 L.InitList();
265 printf("Please input a number n.\n");
266 scanf("%d", &n);
267 printf("Please input n+1 numbers means a0+a1*x+a2*x^2+...+an*x^n.\n");
268 for(i = 1; i <= n + 1; i++)
269 {
270 scanf("%d", &Elem);
271 L.ListInsert(i, Elem);
272 }
273 }
274
275 int main()
276 {
277 MyList La, Lb;
278 Read(La);
279 Read(Lb);
280 printf("La(x) = ");
281 La.PrintList_ForPolynomial();
282 printf("Lb(x) = ");
283 Lb.PrintList_ForPolynomial();
284 La.AddList(Lb);
285 printf("La(x) + Lb(x) = ");
286 La.PrintList_ForPolynomial();
287 return 0;
288 }

最新文章

  1. jQuery.data() 使用方法
  2. 如果你想深刻理解ASP.NET Core请求处理管道,可以试着写一个自定义的Server
  3. tomcat(二)--tomcat结构
  4. js页面跳转整理(转载未整理)
  5. 文件压缩与挤压ZIP
  6. .net 测试工具类
  7. Android Activity 生命周期详解
  8. WebService使用入门(包括发布服务,调用服务)
  9. python的eval函数
  10. Regular Express 匹配中文,所有中文标点符号
  11. 程序猿职业生涯中的 Norris 常数
  12. 单调性优化DP
  13. 深度学习(十) GoogleNet
  14. java 并发(七)--- ThreadLocal
  15. 见到Unicode、GB2312、GBK 、ANSI、Ascii、DBCS、BIG5、UTF这一堆名词你是否犯晕?请看转载的好文
  16. react native组件的创建
  17. jquery ui的css设计
  18. (转)Uri详解之——Uri结构与代码提取
  19. opencv3读取视频并保存为图片
  20. idea实时编译代码

热门文章

  1. linux与shell介绍 - 进程与线程
  2. 桥接模式(Bridge模式)
  3. gorm中的基本查询
  4. java关键字final
  5. 【程序15】成绩>=90分用A表示,60-89分用B表示, 60分以下用C表示。
  6. socket编程(struct报头)网络编程
  7. 这个命令行HTTP客户端工具真不错
  8. 分享一个基于 ABP(.NET 5.0) + vue-element-admin 管理后台
  9. 学习Java第3天
  10. docker镜像制作Dockerfile