一、问题描述
一元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 #include2 #include 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,失败时返回true105 {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 else119 {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返回,错误时返回true132 {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 else146 {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,失败返回true183 {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 else249 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 else257 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 }