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