一元多项式相乘链表的实现

一、题目

将两个一元多项式相乘,最后将相乘的结果输出。

一元多项式指数默认递增。输入时依次输入每项系数和指数。

比如:

多项式A:1+2*x-4*x^4

多项式B:2-2*x+5^x^4

输入:

0 1 2 1 -4 4 0 0

2 0 -2 1 5 4 0 0

输出:

2 0 2 1 -4 2 -3 4 18 5 -20 8

代码重写

博客下面有留言,说代码错了。我确认了下,确实是错误的,输出结果不对

这还是我上学那会写的代码,而我又很久不写C语言的代码了。。

这道题目有两个难点:其一是数据结构--链表的实现;其二是多项式链表的乘法。

PS: 本文完整代码见仓库03-linked-multi

先看第一点,链表结构的实现。我很久没写C语言了,也不想重新撸一遍链表结构。我之前在用户空间使用过linux内核的双链表结构,见:linux内核链表结构。所以,上网找了下,在Can I use Linux kernel linked list outside kernel code?中看到~kazutomo/list/list.h。链接中的代码,是个双链表。我们可以直接拿过来用,该双链表的函数接口,仍然遵循List Management Functions。我建议读下这个双链表结构的代码,质量还不错。

再来看第二点,多项式的乘法。一遍计算,一遍合并就好。大体过程如下。

下面是链表相乘部分的代码。双链表(list.h)的代码,见上面链接,或者上面仓库。

#include "list.h"
#include <stdio.h>

/**
 * 链表相乘:(1+2x-4x^4) * (2-2x+5x^4) = (2+2x-4x^2-3x^4+18x^5-20x^8)
 * 输入时依次输入每项系数和指数(系数和指数都为0结束):
 * 注:输入假定,一元多项式已按照指数进行非降序排列
 * 1 0 2 1 -4 4
 * 2 0 -2 1 5 4
 * 输出:
 * 2 0 2 1 -4 2 -3 4 18 5 -20 8
 */

typedef struct _node {
  struct list_head list;
  int coeff; // 系数
  int expon; // 指数
} node;

void print_linked(node *head) {
  struct list_head *pos;
  list_for_each(pos, &head->list) {
    node *entry = list_entry(pos, node, list);
    printf("coeff: %d, expon: %d\n", entry->coeff, entry->expon);
  }
}

void create_linked(node *head, int info[], int len) {
  for (int i = 0; i < len; i += 2) {
    if ((i + 1 < len) && (info[i] != 0 || info[i + 1] != 0)) {
      node *elem = (node *)malloc(sizeof(node));
      elem->coeff = info[i];
      elem->expon = info[i + 1];
      list_add_tail(&elem->list, &head->list);
    } else {
      ;
    }
  }
}

void destroy_linked(node *head) {
  node *elem, *tmp;
  list_for_each_entry_safe(elem, tmp, &head->list, list) {
    list_del(&elem->list);
    free(elem);
  }
}

void multi_linked(node *linked_a, node *linked_b, node *linked_c) {
  struct list_head *pos_a;
  struct list_head *pos_b;
  struct list_head *pos_c;

  list_for_each(pos_a, &linked_a->list) {
    node *entry_a = list_entry(pos_a, node, list);
    int coeff_a = entry_a->coeff;
    int expon_a = entry_a->expon;
    list_for_each(pos_b, &linked_b->list) {
      node *entry_b = list_entry(pos_b, node, list);
      int coeff_b = entry_b->coeff;
      int expon_b = entry_b->expon;

      node *elem = (node *)malloc(sizeof(node));
      elem->coeff = coeff_a * coeff_b;
      elem->expon = expon_a + expon_b;
      if (list_empty(&linked_c->list)) { // 存储结果的链表为空,直接插入
        list_add_tail(&elem->list, &linked_c->list);
      } else {
        list_for_each(pos_c, &linked_c->list) {
          node *entry_c = list_entry(pos_c, node, list);
          int coeff_c = entry_c->coeff;
          int expon_c = entry_c->expon;
          if (elem->expon < expon_c) {
            // 指数非降序,遇到第一个大于elem的指数,插入它之前
            list_add(&elem->list, pos_c->prev);
            break;
          } else if (elem->expon == expon_c) {
            // 指数非降序,遇到等于elem的指数,合并
            entry_c->coeff += elem->coeff;
            break;
          } else {
            // 指数非降序,遇到小于elem的指数,通常是继续向后找
            // 如果此时是查找的最后一个元素--即,elem的指数最大,直接插入到最后
            if (pos_c->next == &linked_c->list) {
              list_add(&elem->list, pos_c);
              break;
            }
          }
        }
      }
    }
  }
}

int main(int argc, char *argv[]) {
  node linked_a;
  node linked_b;
  node linked_c;

  INIT_LIST_HEAD(&linked_a.list);
  INIT_LIST_HEAD(&linked_b.list);
  INIT_LIST_HEAD(&linked_c.list);

  int a_info[] = {1, 0, 2, 1, -4, 4};
  int b_info[] = {2, 0, -2, 1, 5, 4};

  create_linked(&linked_a, a_info, sizeof(a_info) / sizeof(a_info[0]));
  print_linked(&linked_a);
  printf("----------------------\n");
  create_linked(&linked_b, b_info, sizeof(b_info) / sizeof(b_info[0]));
  print_linked(&linked_b);
  printf("----------------------\n");

  multi_linked(&linked_a, &linked_b, &linked_c);
  print_linked(&linked_c);

  destroy_linked(&linked_a);
  destroy_linked(&linked_b);
  destroy_linked(&linked_c);

  return 0;
}

编译与输出如下。

gcc.exe main.c -o main
./main

coeff: 1, expon: 0
coeff: 2, expon: 1
coeff: -4, expon: 4
----------------------
coeff: 2, expon: 0
coeff: -2, expon: 1
coeff: 5, expon: 4
----------------------
coeff: 2, expon: 0
coeff: 2, expon: 1
coeff: -4, expon: 2
coeff: -3, expon: 4
coeff: 18, expon: 5
coeff: -20, expon: 8

后面为错误代码,未删除。可跳过。

二、题目分析

首先得会一元多项式的相加:点击打开链接

注意:如果单纯的使用多个一元多项式相加,由于不知道链表的长度,不能建立与链表长度数相同的多项式个数。则需重新建立新链表在其上累加,且保证要相加两链表的不变。

一种写法是利用递归函数。还有一种是利用循环。

建立链表可以用单链表,由于多次用到所指元素的前一个节点,也可以用双向链表。

下面是利用单链表及循环实现目标。

#include<stdio.h>
#include<stdlib.h>
typedef struct Node
{
	int coef;//coefficient:系数
	int index;//index:指数
	struct Node *next; 
}node;

node *creat()
{
	int coef,index;
	node *head,*p;
	head=(node *)malloc(sizeof(node));
	p=head;
	while(1)//系数和指数都为0,作为结束标识 
	{
		scanf("%d",&coef);
		scanf("%d",&index);
		if(coef==0&&index==0)
			break;
		p->next=(node *)malloc(sizeof(node));
		p=p->next;
		p->coef=coef;
		p->index=index;
	}
	p->next=NULL;
	return head;
} 

node *ridepolylist(node *la,node *lb)//ride:乘
{
	int temp1,temp2;
	node *p;
	node *lc;
	node *pa,*pb,*pc;
	node *pc1,*pc2; 
	pa=la->next;
	pb=lb->next;
	//复制la指数到lc中 
	lc=(node *)malloc(sizeof(node));
	lc=pc;
	while(pa)
	{
		pc->next=(node *)malloc(sizeof(node));
		pc=pc->next;
		pc->coef=0;//lc初始化系数为0 
		pc->index=pa->index;
		pa=pa->next;
	} 
	pc->next=NULL; 
	//复制完成
	//逐项相乘 
	pa=la->next;
	while(pa)
	{
		pb=lb->next;
		while(pb)
		{
			pc1=lc;
			pc2=pc1->next;
			temp1=(pa->coef)*(pb->coef);
			temp2=(pa->index)+(pb->index);
			while(pc2)//寻找在lc中位置 
			{
				if(pc2->index<temp2)
				{
					pc1=pc2;
					pc2=pc1->next;
				}
				else if(pc2->index==temp2)
				{
					pc2->coef=pc2->coef+temp1;//如果是0进行最后处理 
					break;
				}
				else
				{
					//这里要插在前方,用单项链表不好写,建立时应该用双向链表 
					p=(node *)malloc(sizeof(node));
					p->coef=temp1;
					p->index=temp2;
					pc1->next=p;
					p->next=pc2;
					break;
				}	
			}
			if(!pc2)//插在最后位置
			{
				p=(node *)malloc(sizeof(node));
				p->coef=temp1;
				p->index=temp2;
				pc1->next=p;
				p->next=NULL; 
			}
			pb=pb->next; 
		}
		pa=pa->next;
	}
	return lc;	
} 


node *delay0elem(node *lc)//删除 
{
	node *p,*q;
	p=lc;
	q=p->next;
	while(q)
	{
		if(q->coef==0)
		{
			p->next=q->next;
		}
		p=q;
		q=p->next;
	}
	return lc;
}

void pri(node *head)
{
	node *p;
	p=head->next;
	while(p)
	{
		printf("+%d*x^%d ",p->coef,p->index);
		p=p->next;
	}
	printf("\n");
}


void main()
{
	node *creat();
	node *ridepolylist(node *la,node *lb);
	node *delay0elem(node *lc);
	void pri(node *head);
	
	node *la,*lb,*lc;
	
	printf("输入多项式la,以0 0作为结束标识:"); 
	la=creat();
	pri(la);
	
	printf("输入多项式lb,以0 0作为结束标识:");
	lb=creat();
	pri(lb);
	
	printf("输出两多项式乘机lc:");
	lc=ridepolylist(la,lb); 
	lc=delay0elem(lc);
	pri(lc);
}

	pri(lc);
}

四、代码分析lc链表初始化时,复制了la.这步可以省略。它可以包含在创立新节点的情况里。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

da1234cao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值