第三章 表、栈和队列(三)

github地址:https://github.com/wyd933/datastructure

挖坑:

关于基数排序我想到一个Hash列表处理的好方法,后面写

 

用链表实现一个多项式的加法和乘法。

内容介绍:

    链表直接采用list.h的基本操作,并加以封装。主要是希望链表可以类似于继承的、面向对象程序的方式进行操作。

这样做的好处就是,所有关于链表的操作均以一套API完成。任何需要链表的结构,只要集成这个结构体,就能满足

链表的所有操作。这是面向对象的方法。

 

一些困难:

1、开始的时候有必要加头结点,在编写过程中尝试无头的方法,写到后来发现必须有个判定标志。

于是加了一个系数为零的节点作为末尾,后来优化代码改为链表头,好写了很多,逻辑也更清晰。

关于有头无头之争,我还是选择了有头,虽然我认为无头更合理,但是有头链表更好写,逻辑更易读。

 

代码分解:

基本结构

//error
//expected ‘;’ before ‘}’ token
// #define LIST_HEAD_INIT(name) { &(name), &(name) }


#define LIST_HEAD_INIT(name) { &(name), &(name) }

#define LIST_HEAD(name) \
	struct list_head name = LIST_HEAD_INIT(name)

struct list_head 
{
    struct list_head *prev, *next;
};

struct node
{
    int Coefficient;
    int Exponent;
    struct list_head list_node;
};
typedef struct node *Polynomial;

//#define offsetof(TYPE, MEMBER)	((size_t)&((TYPE *)0)->MEMBER)

#define container_of(ptr, type, member) ({				\
	void *__mptr = (void *)(ptr);					\
	((type *)(__mptr - offsetof(type, member))); })

#define list_entry(ptr, type, member) \
	container_of(ptr, type, member)

#define list_next_entry(pos, member) \
	list_entry((pos)->member.next, typeof(*(pos)), member)

#define list_prev_entry(pos, member) \
	list_entry((pos)->member.prev, typeof(*(pos)), member)

#define list_first_entry(ptr, type, member) \
	list_entry((ptr)->next, type, member)


#define list_for_each_entry(pos, head, member)				\
	for (pos = list_first_entry(head, typeof(*pos), member);	\
	     &pos->member != (head);					\
	     pos = list_next_entry(pos, member))

void __list_add(struct list_head *new,	\
			      struct list_head *prev,	\
			      struct list_head *next);

void list_add(struct list_head *new, struct list_head *head);

Polynomial Init_Poly();

Polynomial Sort_Poly(Polynomial P);

Polynomial AddPolynomial(const Polynomial Poly1,\
				const Polynomial Poly2, Polynomial PolySum);

 

1)链表的基础操作

void __list_add(struct list_head *new,	\
			      struct list_head *prev,	\
			      struct list_head *next)
{
	next->prev = new;
	new->next = next;
	new->prev = prev;
	prev->next = new;
}
//stack
void list_add(struct list_head *new, struct list_head *head)
{
	__list_add(new, head, head->next);
}

void __list_del(struct list_head * prev, struct list_head * next)
{
	next->prev = prev;
	prev->next = next;
}

void __list_del_entry(struct list_head *entry)
{
	__list_del(entry->prev, entry->next);
}

void INIT_LIST_HEAD(struct list_head *list)
{
	list->next = list;
	list->prev = list;
}
void list_del_init(struct list_head *entry)
{
	__list_del_entry(entry);
	INIT_LIST_HEAD(entry);
}

2)一个多项式单元的创建和整个多项式的删除

Polynomial Init_Poly()
{
	Polynomial poly;
	poly = malloc(sizeof(struct node));
	poly->list_node.prev = &poly->list_node;
	poly->list_node.next = &poly->list_node;
	return poly;
}

void Del_Poly_List(Polynomial poly)
{
	Polynomial p1 = list_entry(poly->list_node.next,struct node, list_node);
	while(p1->Coefficient)
	{
		list_del_init(&p1->list_node);
		free(p1);
		p1 = list_entry(poly->list_node.next,struct node, list_node);
	}
}

3)多项式加法,传入两个多项式,以及保留结果的节点,返回整个多项式的结果

加法需要同指数相加,如果一个链表没有按照指数排序.,可以如下操作:

       选择一个链表,每节点循环与另一个链表同指数节点相加,

       需要循环n×n次+新链表制作时间。而且结果链表无序。

如果每个链表先排序,按顺序相加,时间是2×t(链表排序)+ 新链表制作时间

为了保证一致性,以及便于判断,做了一个队列头,因为多项式不写系数为零的项,所以头结点系数指数均为0

 

一些看法:

循环链表判断队列尾很恶心,用循环队列算过度设计

如果不是为了体验内核链表这种类似于被继承的方式,建议单链表,最好数组,数组最简单。

因为数组可以用偏移量代表指数,存储系数,问题是内存空间开销会大

 

//排序好的链表,按照指数大小依次插入到新的节点

//如果不排序传入AddPolynomial函数会有BUG。

//如果使用好的排序方法,该函数会比不排序链表省时间,前提是链表排序时间复杂度要比N方小

 

参数Poly1和Poly2是已知的两个多项式链表,PolySum是要传入的头结点,返回一个和的链表,

返回链表的头结点为PolySum。

 

其实不传头结点或许更好,选择传入头结点是为了让使用者可以参与开头位置的制定,有一定的掌控力。

不传头结点,则有一定的保密性

Polynomial AddPolynomial(const Polynomial Poly1,\
				const Polynomial Poly2, Polynomial PolySum)
{
	Polynomial p1 = list_entry(Poly1->list_node.next,struct node, list_node);
	Polynomial p2 = list_entry(Poly2->list_node.next,struct node, list_node);
	Polynomial first, before, temp, pos;
	first = PolySum;
	while(p1->Coefficient || p2->Coefficient)
	{
		if((p1->Exponent < p2->Exponent && p1->Coefficient != 0) || p2->Coefficient == 0)
		{
			
			temp = Init_Poly();
			temp->Exponent = p1->Exponent;
			temp->Coefficient = p1->Coefficient;
			list_add(&temp->list_node, &PolySum->list_node);
			PolySum= temp;
			temp = NULL;
			p1 = list_entry(p1->list_node.next,struct node, list_node);
		}
		else if(p1->Exponent == p2->Exponent)
		{
			temp = Init_Poly();
			temp->Exponent = p1->Exponent;
			temp->Coefficient = p1->Coefficient + p2->Coefficient;
			list_add(&temp->list_node, &PolySum->list_node);
			PolySum = temp;
			temp = NULL;
			p1 = list_entry(p1->list_node.next,struct node, list_node);
			p2 = list_entry(p2->list_node.next,struct node, list_node);
		}
		else
		{
			temp = Init_Poly();
			temp->Exponent = p2->Exponent;
			temp->Coefficient = p2->Coefficient;
			list_add(&temp->list_node, &PolySum->list_node);
			PolySum = temp;
			temp = NULL;
			p2 = list_entry(p2->list_node.next,struct node, list_node);
		}	
	}
	return first;
}

4)多项式乘法

乘法和加法的区别在于排序,但是之前的加法我是基于排序的。

所以乘法做完之后多项式加法比较简单

Polynomial MulPolynomial(const Polynomial Poly1,\
				const Polynomial Poly2, Polynomial PolyMul)
{
	Polynomial head1 = Poly1;
	Polynomial head2 = Poly2;
	Polynomial headMul = PolyMul;
	Polynomial p1,p2;
	Polynomial temp, before, first, pos, prev, next;
	for(p1 = list_entry(head1->list_node.next,struct node, list_node);\
		 p1->Coefficient; 	\
		 p1 = list_entry(p1->list_node.next,struct node, list_node))
		for(p2 = list_entry(head2->list_node.next,struct node, list_node);\
			 p2->Coefficient != 0; \
			 p2 = list_entry(p2->list_node.next,struct node, list_node))
		{
			temp = Init_Poly();
			temp->Exponent = p1->Exponent + p2->Exponent;
			temp->Coefficient = p1->Coefficient * p2->Coefficient;
			list_add(&temp->list_node, &PolyMul->list_node);
			PolyMul = temp;
			temp = NULL;
		}
		PolyMul = Sort_Poly(headMul);
		
		prev = PolyMul;
		next = list_next_entry(prev, list_node);
		for(; next->Coefficient != 0;)
		{
			if(prev->Exponent == next->Exponent)
			{
				prev->Coefficient = prev->Coefficient + next->Coefficient;
				list_del_init(&next->list_node);
				free(next);
				next = list_next_entry(prev, list_node);
			}
			else
			{
				prev = next;
				next = list_next_entry(prev, list_node);
			}
		} 
 		for (pos = list_entry(PolyMul->list_node.next,struct node,list_node);	\
	     	pos->Coefficient != 0;					\
	     	pos = list_next_entry(pos, list_node))
		{
			printf("%dx%d\n",pos->Coefficient,pos->Exponent);
		} 
		return PolyMul;
}

5)多项式排序

这个是加法和乘法的基础,没什么难点

Polynomial Sort_Poly(Polynomial p)
{
	int ischange=1;
	Polynomial end, first;
	end = first = p;
	Polynomial prev = list_entry(p->list_node.next,struct node, list_node);
	Polynomial next = list_entry(prev->list_node.next,struct node, list_node);
	
	if(first->list_node.next == &first->list_node)
		return NULL;

	if(prev->list_node.next == &first->list_node)	
		return NULL;
		
	while(ischange)
	{	
		ischange = 0;
		for(;next->Coefficient != end->Coefficient;)
		{
 			ischange = 1;
			if(prev->Exponent > next->Exponent)
			{ 
				Swap_Poly(prev,next);
				next = list_entry(prev->list_node.next,struct node,list_node);	
  			}
			else
			{
				prev = next;
				next = list_entry(prev->list_node.next,struct node,list_node);
			} 
		}
 		end = prev;
		prev = list_entry(first->list_node.next,struct node,list_node);
		next = list_entry(prev->list_node.next,struct node,list_node); 
	}
	return first;
}

6)测试代码

int main()
{
	Polynomial Poly1, Poly2, PolySum, pos, head1, head2, temp, headSum, PolyMul;
	int i;

	Poly1 = Init_Poly();
	Poly1->Exponent = 0;
	Poly1->Coefficient = 0;
	head1 = Poly1;
	
	Poly2 = Init_Poly();
	Poly2->Coefficient = 0;
	Poly2->Exponent = 0;
	head2 = Poly2;

	PolySum = Init_Poly();
	PolySum->Coefficient = 0;
	PolySum->Exponent = 0;
	headSum = PolySum;

	PolyMul = Init_Poly();
	PolyMul->Coefficient = 0;
	PolyMul->Exponent = 0;
	PolyMul = PolySum;

	for(i = 3; i > 0; i -= 1)
	{
		temp = Init_Poly();
		temp->Exponent = i;
		temp->Coefficient = i;
		list_add(&temp->list_node, &Poly1->list_node);
		Poly1 = temp;
		temp = NULL;
	}
	
	Poly1 = Sort_Poly(head1);

	for (pos = list_entry(head1->list_node.next,struct node,list_node);	\
	     pos->Coefficient != 0;					\
	     pos = list_next_entry(pos, list_node))
	{
		printf("%dx%d\n",pos->Coefficient,pos->Coefficient);
	}


	for(i = 1; i < 3; i += 1)
	{
		temp = Init_Poly();
		temp->Exponent = i;
		temp->Coefficient = i;
		list_add(&temp->list_node, &Poly2->list_node);
		Poly2 = temp;
		temp = NULL;
		printf("ddd%d\n", Poly2->Coefficient);
	}
	
	Poly2 = Sort_Poly(head2);

	for (pos = list_entry(head2->list_node.next,struct node,list_node);	\
	     pos->Coefficient != 0;					\
	     pos = list_next_entry(pos, list_node))
	{
		printf("%dx%d\n",pos->Coefficient,pos->Coefficient);
	}

	//PolySum = AddPolynomial(Poly1,Poly2,PolySum);
	MulPolynomial(Poly1,Poly2,PolySum); 
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章