一、问题描述

一元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 }

[数据结构]一元n次多项式的抽象数据类型的更多相关文章

  1. 【Python&数据结构】 抽象数据类型 Python类机制和异常

    这篇是<数据结构与算法Python语言描述>的笔记,但是大头在Python类机制和面向对象编程的说明上面.我也不知道该放什么分类了..总之之前也没怎么认真接触过基于类而不是独立函数的Pyt ...

  2. 数据结构 集合_集合(数学)抽象数据类型的C语言实现

    链表是实现集合的一种理想的方式.将List以typedef的方式重命名为Set.这样做能保留链表简洁的特性,还能使集合具有了一些多态的特性. 使用这种方法的最大好处就是可以使用list_next来遍历 ...

  3. C语言泛型编程--抽象数据类型

    一.数据类型: 在任何编程语言中,数据类型作为一个整体,ANSI-C包含的类型为:int.double.char……,程序员很少满意语言本身提供的数据类型,一个简单的办法就是构造类似:array.st ...

  4. ORACLE抽象数据类型

    ORACLE抽象数据类型 *抽象数据类型*/1,抽象数据类型 概念包含一个或多个子类型的数据类型不局限于ORACLE的标准数据类型可以用于其他数据类型中 2,创建抽象数据类型 的语法(必须用NOT F ...

  5. Week1绪论--抽象数据类型

    一.作业题目 1.构造有理数T,元素e1,e2分别被赋以分子.分母值 2.销毁有理数T 3.用e(引用类型参数)返回有理数T的分子或分母,当入参i为1时返回分子, i为2是返回分母. 4.将有理数T的 ...

  6. DS博客作业01--日期抽象数据类型设计与实现

    1.思维导图及学习体会 1.1第一章绪论知识点思维导图 1.2 学习体会 这次博客园和大作业是我在编程学习中的有意义的进步,第一次尝试使用vs,并且通过同学的一些网站的推荐,和热心同学的帮忙,简单学会 ...

  7. 抽象数据类型(ADT)

    概念 抽象数据类型(ADT),脱离具体实现定义数据结构,它的定义着重于做什么,而忽略怎么做 举例 列表.栈.队列 列表 列表,也叫线性表 抽象定义:数据项线性排列,可以插入某一项,删除某一项,读取某一 ...

  8. 抽象数据类型ADT

    ADT(Abstract Data Type) 类型由什么组成? 一个类型(type)指定两类信息,一个属性集和一个操作集. 假设要定义一个新的数据类型.首先,要提供存储数据的方式,可能是通过设计一个 ...

  9. ADT(abstract data types)抽象数据类型

    1.What is it? An abstract data type is a set of objects together with a set of operations. 抽象数据类型是带有 ...

随机推荐

  1. MySQL数据库学习打卡 DAY2

    今天学习了MySQL的DML操作,完成了关于增删改查所有基本内容的学习.

  2. C#服务器端使用office组件

    http://www.myexception.cn/asp-dotnet/386522.html 不装office那就把Interop.Excel.dll Interop.Office.dll Int ...

  3. Tomcat-如何在IDEA启动部署web模板

    IDEA部署工程到Tomcat上运行 1,建议修改web工程对应的Tomcat运行实例名称 2,将需要部署的web工程添加到Tomcat运行实例中,添加或删除 Application context: ...

  4. openstack,docker,mesos,Kubernetes(k8s)

    作者:张乾链接:https://www.zhihu.com/question/62985699/answer/204233732来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明 ...

  5. 微前端框架 之 single-spa 从入门到精通

    前序 目的 会使用single-spa开发项目,然后打包部署上线 刨析single-spa的源码原理 手写一个自己的single-spa框架 过程 编写示例项目 打包部署 框架源码解读 手写框架 关于 ...

  6. 服务器+nextcloud搭建自己的私有云盘

    简介 Nextcloud是一款开源免费的私有云存储网盘项目,可以让你快速便捷地搭建一套属于自己或团队的云同步网盘,从而实现跨平台跨设备文件同步.共享.版本控制.团队协作等功能.它的客户端覆盖了Wind ...

  7. APC 篇—— APC 执行

    写在前面   此系列是本人一个字一个字码出来的,包括示例和实验截图.由于系统内核的复杂性,故可能有错误或者不全面的地方,如有错误,欢迎批评指正,本教程将会长期更新. 如有好的建议,欢迎反馈.码字不易, ...

  8. 如何将EDI报文转换为CSV格式文件?

    如果您对EDI项目实施有一定的了解,想必您一定知道,在正式开始EDI项目实施之前,都会有EDI顾问与您接洽,沟通EDI项目需求.其中,会包含EDI通信双方使用哪种传输协议,传输的报文是符合什么标准的, ...

  9. .NET 诞生已20周年,您的 .NET 技能是否还停留在2010 年?

    20年来,我们见证了超过上千万.NET 开发员,当前有600万.NET 开发者正在使用.NET技术构建各类解决方案.今天,IT市场对.NET 开发人员的需求达到了前所未有的程度,特别是在中国,各大公司 ...

  10. bash_profile和bashsrc的区别

    感谢大佬:http://unclealan.cn/index.php/system/128.html 描述 在类Linux或者MACOS系统中,家目录(用户目录)中我们会看到,.bash_profil ...