[数据结构]一元n次多项式的抽象数据类型
一、问题描述
一元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次多项式的抽象数据类型的更多相关文章
- 【Python&数据结构】 抽象数据类型 Python类机制和异常
这篇是<数据结构与算法Python语言描述>的笔记,但是大头在Python类机制和面向对象编程的说明上面.我也不知道该放什么分类了..总之之前也没怎么认真接触过基于类而不是独立函数的Pyt ...
- 数据结构 集合_集合(数学)抽象数据类型的C语言实现
链表是实现集合的一种理想的方式.将List以typedef的方式重命名为Set.这样做能保留链表简洁的特性,还能使集合具有了一些多态的特性. 使用这种方法的最大好处就是可以使用list_next来遍历 ...
- C语言泛型编程--抽象数据类型
一.数据类型: 在任何编程语言中,数据类型作为一个整体,ANSI-C包含的类型为:int.double.char……,程序员很少满意语言本身提供的数据类型,一个简单的办法就是构造类似:array.st ...
- ORACLE抽象数据类型
ORACLE抽象数据类型 *抽象数据类型*/1,抽象数据类型 概念包含一个或多个子类型的数据类型不局限于ORACLE的标准数据类型可以用于其他数据类型中 2,创建抽象数据类型 的语法(必须用NOT F ...
- Week1绪论--抽象数据类型
一.作业题目 1.构造有理数T,元素e1,e2分别被赋以分子.分母值 2.销毁有理数T 3.用e(引用类型参数)返回有理数T的分子或分母,当入参i为1时返回分子, i为2是返回分母. 4.将有理数T的 ...
- DS博客作业01--日期抽象数据类型设计与实现
1.思维导图及学习体会 1.1第一章绪论知识点思维导图 1.2 学习体会 这次博客园和大作业是我在编程学习中的有意义的进步,第一次尝试使用vs,并且通过同学的一些网站的推荐,和热心同学的帮忙,简单学会 ...
- 抽象数据类型(ADT)
概念 抽象数据类型(ADT),脱离具体实现定义数据结构,它的定义着重于做什么,而忽略怎么做 举例 列表.栈.队列 列表 列表,也叫线性表 抽象定义:数据项线性排列,可以插入某一项,删除某一项,读取某一 ...
- 抽象数据类型ADT
ADT(Abstract Data Type) 类型由什么组成? 一个类型(type)指定两类信息,一个属性集和一个操作集. 假设要定义一个新的数据类型.首先,要提供存储数据的方式,可能是通过设计一个 ...
- ADT(abstract data types)抽象数据类型
1.What is it? An abstract data type is a set of objects together with a set of operations. 抽象数据类型是带有 ...
随机推荐
- PWA 技术落地!让你的站点(Web)秒变APP(应用程序)
Web应用方兴未艾,我们已经十分习惯习惯了在电脑上进行以自己的工作,而随着众多功能强大的在线网站,我们的Windows的桌面也不再拥挤着各种快捷方式:不光是PC端,在移动端我们也不再在浩如烟海的应用市 ...
- 【刷题-LeetCode】164 Maximum Gap
Maximum Gap Given an unsorted array, find the maximum difference between the successive elements in ...
- 根据happens-before法则借助同步
在文章的开始,我们先来看一段代码以及他的执行情况: public class PossibleRecording{ static int x = 0, y = 0; static int a = 0, ...
- QT之键盘事件
Widget.h: #ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include<QKeyEvent> #incl ...
- 科技爱好者周刊(第 174 期):全能程序员 vs 特长程序员
这里记录每周值得分享的科技内容,周五发布. 本杂志开源(GitHub: ruanyf/weekly),欢迎提交 issue,投稿或推荐科技内容. 周刊讨论区的帖子<谁在招人?>,提供大量程 ...
- (1)puppet安装
简介: 基于C/S架构的Puppet更新方式一般有两种,一种是Agent端设置同步时间主动去PuppetMaster端拉取配置,另一种是通过PuppetMaster端使用puppet kick命令或者 ...
- 深入了解promise
1. Promise基础 什么是回调地狱? 当使用回调函数来进行事件处理的时候,如果嵌套多层回调函数的时候,就会出现回调地狱,例如: method1(function(err, result) { i ...
- 使用VSCode在本地电脑上对树莓派远程开发
目的及原理 有时身边没有额外的显示器和键盘,或者有时树莓派在另一个屋子连接着路由器,那么当我们想在树莓派上做开发时就可以使用VS Code的远程开发能力.下面一张图显而易见地说明了远程开发的工作原理( ...
- django之集成七牛云对象存储
Python3 + Django2.0 集成 "七牛云" 对象存储 (SDK文档地址:http://developer.qiniu.com/kodo/api/3928/error- ...
- 如何在pyqt中实现win10亚克力效果
亚克力效果的实现思路 上一篇博客<如何在pyqt中实现窗口磨砂效果> 中实现了win7中的Aero效果,但是和win10的亚克力效果相比,Aero还是差了点内味.所以今天早上又在网上搜了一 ...