第三章 表、棧和隊列(三)鏈表的實現和多項式的實現

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); 
}

 

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