文字描述
在数学上,一个一元多项式可以按升幂写成如下形式。
它由n+1个系数唯一确定。因此,在计算机里,可以用一个线性表P来表示,P中每一项的指数i隐含在其系数pi的序号里。
但是在通常的应用中,多项式的次数可能很高且变化很大,使得顺序存储结构的最大长度很难确定。比如如下多项式,就要用一个长度为20001的线形表来表示,表中仅有3个非零元素,这种会极其浪费内存空间。
针对上面这种情况,可以在线形表中只存放非零的元素,每个元素有两个数据项(系数项和指数项),如下。这便可唯一确定多项式Pn(x)。在最坏情况下,n+1(=m)个系数都不为零,则比只存储每项系数的方案要多存储一倍的数据。
示意图
算法分析
多项式的相加过程和之前讨论的归并两个有序表的过程很类似。时间复杂度同单向链表的归并算法相同。
代码实现
1 // 2 // Created by lady on 19-2-17. 3 // 4 5 #include6 #include 7 8 typedef struct { 9 float coef;//系数 10 int expn;//指数 11 }term, ElemType; 12 13 typedef struct LNode{//结点类型 14 ElemType e; 15 struct LNode *next; 16 }*Link; 17 18 typedef struct {//链表类型 19 Link head;//指向线性链表中的头结点 20 }LinkList; 21 22 typedef LinkList polynomial;//用带表头结点的有序链表表示多项式 23 24 //构造一个空的线性链表L 25 static int InitList(LinkList *L) 26 { 27 if(L == NULL) 28 return -1; 29 Link p = (Link)malloc(sizeof(struct LNode)); 30 p->next = NULL; 31 L->head = p; 32 return 0; 33 } 34 35 //返回链表L的头结点 36 static Link GetHead(LinkList *L){ 37 if(L==NULL){ 38 return NULL; 39 } 40 return L->head; 41 } 42 43 //设置p结点的数据元素值为e 44 static void SetCurElem(Link p, ElemType e) 45 { 46 p->e = e; 47 return 0; 48 } 49 50 //返回线性表L中第1个与e满足函数fun判定关系的元素的位置,并用q指示其结点地址值 51 static int LocateElem(LinkList *L, ElemType e, Link *q, int (*fun)(term, term)) 52 { 53 Link p = L->head->next; 54 (*q) = L->head; 55 while(p){ 56 if(fun(p->e, e) == 0){ 57 (*q) = p; 58 return 0; 59 } 60 (*q) = p; 61 p = p->next; 62 } 63 return -1; 64 } 65 66 //已知h指向线性表的头结点,将s所指结点插入在第一个结点之前 67 static int InsFirst(Link *h, Link *s) 68 { 69 if(h==NULL || s==NULL){ 70 return -1; 71 } 72 if(*h == NULL || *s == NULL){ 73 return -1; 74 } 75 (*s)->next = (*h)->next; 76 (*h)->next = (*s); 77 return 0; 78 } 79 80 //创建新的结点,其地址值为*p, 结点值为e 81 static int MakeNode(Link *p, ElemType e) 82 { 83 if(p==NULL){ 84 return -1; 85 } 86 if(((*p) = (Link)malloc(sizeof(struct LNode))) == NULL){ 87 return -1; 88 } 89 (*p)->next = NULL; 90 (*p)->e = e; 91 return 0; 92 } 93 94 //返回链表L中p结点的后继 95 static Link NextPos(LinkList *L, Link p) 96 { 97 if(L == NULL || p==NULL){ 98 return NULL; 99 } 100 return p->next; 101 } 102 103 //返回结点p的数据元素值 104 static ElemType GetCurElem(Link p) 105 { 106 return p->e; 107 } 108 109 //释放结点及其一系列后面的结点的存储空间 110 static void FreeNode(Link p) 111 { 112 Link q; 113 while(p){ 114 q = p; 115 p = p->next; 116 free(q); 117 } 118 return; 119 } 120 //已知h指向线性链表的头结点,删除链表中的第一个结点并以求返回 121 static int DelFirst(Link *h, Link *q) 122 { 123 if(h==NULL || q==NULL){ 124 return -1; 125 } 126 if(*h == NULL || *q == NULL){ 127 return -1; 128 } 129 (*q) = (*h)->next; 130 (*h)->next = (*q)->next; 131 (*q)->next = NULL; 132 return 0; 133 } 134 135 //返回1-链表为空, 返回0-链表非空 136 static int ListEmpty(LinkList *L) 137 { 138 if(L->head->next == NULL){ 139 return 1; 140 }else{ 141 return 0; 142 } 143 } 144 145 //将指针s所指的一串结点连接到线性链表L的最后一个结点 146 static int Append(LinkList *L, Link *s) 147 { 148 if(L == NULL || s==NULL || *s==NULL){ 149 return -1; 150 } 151 Link p = L->head->next; 152 Link q = L->head; 153 while(p){ 154 q = p; 155 p = p->next; 156 } 157 q->next = (*s); 158 return 0; 159 } 160 161 /* 162 * 依a的指数值<(或=)(或>)b的指数值,分别返回-1、0和+1 163 */ 164 static int cmp(term a, term b) 165 { 166 if(a.expn<b.expn){ 167 return -1; 168 }else if(a.expn == b.expn){ 169 return 0; 170 }else{ 171 return 1; 172 } 173 } 174 175 176 177 //输入m项的系数和指数,建立表示一元多项式的有序链表P 178 static void CreatPolyn(polynomial *P, int m, char note[]){ 179 printf("创建多项式%s!\n", note); 180 int i = 0; 181 Link h; 182 Link s; 183 Link q; 184 ElemType e; 185 InitList(P); 186 h = GetHead(P); 187 e.coef = -1; 188 e.expn = -1; 189 SetCurElem(h, e);//设置头结点的数据元素 190 for(i=1; i<=m; i++){//依次输入m个非零项 191 printf("输入第%d个非0项(系数,指数):", i); 192 scanf("%f,%d[^\\n]", &e.coef, &e.expn); 193 if(LocateElem(P, e, &q, cmp)<0){//如果当前链表中不存在该指数项 194 if(MakeNode(&s, e)==0){//生成结点并插入链表 195 InsFirst(&q, &s); 196 } 197 } 198 } 199 return ; 200 } 201 202 //打印一元多项式 203 static void PrintPolyn(polynomial P, char note[]) 204 { 205 printf("打印输出一元多项式%s: ", note); 206 Link p = P.head->next; 207 while(p){ 208 printf("%.2fx^%d", p->e.coef, p->e.expn); 209 if(p->next){ 210 printf("+"); 211 } 212 p = p->next; 213 } 214 printf("\n"); 215 } 216 217 //多项式加法:Pa=Pa+Pb,利用两个多项式的结点构成"和多项式" 218 static void AddPolyn(polynomial *Pa, polynomial *Pb, char note[]) 219 { 220 printf("多项式相加,%s!\n", note); 221 //ha和hb分别指向Pa和Pb的头结点 222 Link ha = GetHead(Pa); 223 Link hb = GetHead(Pb); 224 //qa和qb分别指向Pa和Pb中的当前结点 225 Link qa = NextPos(Pa, ha); 226 Link qb = NextPos(Pb, hb); 227 ElemType a; 228 ElemType b; 229 ElemType e; 230 while(qa && qb){//qa和qb均非空 231 //a和b为两个表中当前的比较元素 232 a = GetCurElem(qa); 233 b = GetCurElem(qb); 234 switch(cmp(a,b)){ 235 case -1://a 236 ha = qa; 237 qa = NextPos(Pa, qa); 238 break; 239 case 0://a==b,两者的指数值相等 240 e.expn = a.expn; 241 e.coef = a.coef+b.coef; 242 if(e.coef!=0.0){//修改多项式Pa中当前结点的系数值 243 SetCurElem(qa, e); 244 ha = qa; 245 }else{ 246 DelFirst(&ha, &qa); 247 FreeNode(qa); 248 } 249 DelFirst(&hb, &qb); 250 FreeNode(qb); 251 qb = NextPos(Pb, hb); 252 qa = NextPos(Pa, ha); 253 break; 254 case 1://a>b,多项式Pb中当前结点的指数小 255 DelFirst(Pb, &qb); 256 qb->next = NULL; 257 InsFirst(&ha, &qb); 258 qb = NextPos(Pb, hb); 259 qa = NextPos(Pa, ha); 260 break; 261 } 262 } 263 if(ListEmpty(Pb)==0){//链接Pb中剩余结点 264 Append(Pa, &qb); 265 } 266 FreeNode(hb);//释放Pb的头结点 267 return ; 268 } 269 270 int main(int argc, char *argv[]) 271 { 272 polynomial A;//7+3x+9x^8+5x^17 273 polynomial B;//8x+22x^7-9x^8 274 275 CreatPolyn(&A, 4, "A"); 276 PrintPolyn(A, "A"); 277 278 CreatPolyn(&B, 3, "B"); 279 PrintPolyn(B, "B"); 280 281 AddPolyn(&A, &B, "A=A+B"); 282 PrintPolyn(A, "A"); 283 return 0; 284 }
代码运行
/home/lady/CLionProjects/untitled/cmake-build-debug/untitled 创建多项式A! 输入第1个非0项(系数,指数):7,0 输入第2个非0项(系数,指数):3,1 输入第3个非0项(系数,指数):9,8 输入第4个非0项(系数,指数):5,17 打印输出一元多项式A: 7.00x^0+3.00x^1+9.00x^8+5.00x^17 创建多项式B! 输入第1个非0项(系数,指数):8,1 输入第2个非0项(系数,指数):22,7 输入第3个非0项(系数,指数):-9,8 打印输出一元多项式B: 8.00x^1+22.00x^7+-9.00x^8 多项式相加,A=A+B! 打印输出一元多项式A: 7.00x^0+11.00x^1+22.00x^7+5.00x^17 Process finished with exit code 0