1 线性表
1.1 线性表的类型定义
线性表:简单来说,一个线性表是n个数据元素的有限序列。
记录:数据元素(由若干个数据项组成的那些数据元素)。
文件:含有大量记录的线性表。
线性表的长度:即线性表中元素的个数。
位序:元素 a i a_i ai是线性表L的第i个元素,则称i为 a i a_i ai在L中的位序。
同一线性表中的元素是同一数据对象(即具有相同的特性),并相邻的数据元素之间具有序偶关系。若将线性表记为 L = ( a 1 , a 2 , . . . , a n ) L=(a_1,a_2,...,a_n) L=(a1,a2,...,an),则除了第一个数据元素以外其余的都具有一个直接前驱,除了最后一个数据元素以外其余的都具有一个直接后继。
抽象数据类型线性表的定义:
ATD List{
数据对象:D = {ai | ai∈Elemset,i=1,...,n, n>=0}
数据关系:R1 = {<ai-1,ai> | ai-1,ai∈D,i=1,...,n}
基本操作:
InitList(&L)
操作结果:构造了一个空的线性表L。
DestroyList(&L)
初始条件:线性表L已存在。
操作结果:销毁线性表L。
ClearList(&L)
初始条件:线性表L已存在。
操作结果:将线性表L置为空表。
ListEmpty(L)
初始条件:线性表L已存在。
操作结果:若L为空表,则返回True,否则返回False。
ListLength(L)
初始条件:线性表L已存在。
操作结果:返回线性表元素个数。
GetElem(L, i, &e)
初始条件:线性表L已存在,1<= i <=ListLength(L)。
操作结果:用e返回L中第i个元素。
LocateElem(L, e, compare())
初始条件:线性表L已存在,compare()是数据元素的判别函数。
操作结果:返回L中第一个与e满足compare()关系的数据元素的位序,若不存在,返回0。
PriorElem(L, curr_e, &pre_e)
初始条件:线性表L已存在。
操作结果:若curr_e是L的元素且不是第一个,则用pre_e返回其的前驱,否则操作失败,pre_e无定义。
NextElem(L, curr_e, &next_e)
初始条件:线性表L已存在。
操作结果:若curr_e是L的元素且不是最后一个,则用next_e返回其的后继,则操作失败,next_e无定义。
ListInsert(&L, i, e)
初始条件:线性表L已存在,1<= i <=ListLength(L)+1。
操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1。
ListDelete(&L, i, &e)
初始条件:线性表L已存在且非空,1<= i <=ListLength(L)。
操作结果:删除L的第i个元素,用e返回其,L的长度减1。
ListTraverse(L, visit())
初始条件:线性表L已存在。
操作结果:依次对L的每个元素进行visit()操作,一旦visit()失败,则操作失败。
}ADT List
eg1.若两个线性表LA、LB分别表示两个结合A、B,则求线性表LC表示集合C=A∪B。
void union(List &La, List Lb){
//将所有在Lb中但不在La中的数据元素插入到La中
La_len = ListLength(La);
Lb_len = ListLength(Lb);
for(int i=1; i <= Lb_len; i++){
GetElem(Lb, i, e);
if(LocateElem(La, e, equal)){
ListInsert(La, ++La_len, e); //++在前表示先自增再赋值
}
}
}//union
eg2.若LA、LB中的数据元素的按值非递减有序排列,则将LA、LB归并后的线性表LC依然保持值非递减有序排列。
void MergeList(List La, List Lb, List &Lc){
//已知线性表La和Lb中的数据元素按值非递减有序排列
//将La和Lb归并后的线性表Lc中的元素也是按值非递减有序排列
InitList(Lc);
int i=1, j=1, k=0;
La_len = ListLength(La);
Lb_len = ListLength(Lb);
while((i <= La_len) && (j <= Lb_len)){
GetElem(La, i, ai);
GetElem(Lb, j, bj);
if(ai <= bj){
ListInsert(Lc, ++k, ai); i++;
}
else{
ListInsert(Lc, ++k, bj); j++;
}
}
while(i <= La_len){
GetElem(La, i++, ai);
ListInsert(Lc, ++k, ai);
}
while(j <= Lb_len){
GetElem(Lb, j++, bj);
ListInsert(Lc, ++k, bj);
}
}//MergeList
1.2 线性表的顺序表示和实现
顺序表(顺序表示的线性表):用一组地址连续的存储单元存储线性表的数据元素。
基地址(起始地址):线性表的第一个数据元素的存储地址。
第 i i i个元素的地址: L o c ( a i ) = L o c ( a 1 ) + ( i − 1 ) ∗ l Loc(a_i) = Loc(a_1) + (i-1)*l Loc(ai)=Loc(a1)+(i−1)∗l。
L o c ( a 1 ) Loc(a_1) Loc(a1)是基地址, l l l是单个数据元素所占的存储单元。
因此,线性表的顺序存储结构是一种随机存取的存储结构。
// 由于高级程序语言中的数组类型具有随机存取的特性,因此通常以数组来描述顺序存储结构。
//-----------线性表动态分配的顺序存储结构-----------
#define LIST_INIT_SIZE 100
#define LISTINCREMENT 10
typedef struct{
ElemType *elem; //存储空间的基址
int length; //当前的长度
int listsize; //当前分配的存储容量(以sizeof(ElemType)为单位)
}SqList;
Status InitList_Sq(SqList &L){
//构造一个空的线性表L
L.elem = (ElemType*)malloc(LIST_INIT_SIZE * sizeof(ElemType));
if(!L.elem) exit(overflow); //存储失败
L.length = 0; //空表长度为0
L.listsize = LIST_INIT_SIZE; //初始存储容量
}//InitList_Sq
Status ListInsert_Sq(SqList &L, int i, ElemType e){
//在顺序表L的第i个位置插入新的数据元素
//i的合法值为 1<= i <=L.length +1
if((i<1)||(i>L.length+1)) return ERROR;
if(L.length >= L.listsize){
newbase = (ElemType*)malloc((L.listsize + LISTINCREMENT)*sizeof(ElemType));
if(!newbase) exit(overflow);
L.elem = newbase;
L.listsize += LISTINCREMENT;
}
q = &(L.elem[i-1]); //指针q、p
for(p=&(L.elem[L.length-1]); p>=q; p--){
*(p+1) = *p;
}
*q = e;
++L.length;
return OK;
}//ListInsert_Sq
Status ListDelete_sq(SqList &L, int i, ElemType &e){
//在顺序表L中删除第i位置的数据元素
//i的合法值为1<= i <=L.length
if((i<1)||(i>L.length)) return ERROR;
p = &(L.elem[i-1]);
e = *p;
q = &(L.elem[L.length-1]);
for(p++; p<=q; p++){
*(p-1) = *p;
}
L.length--;
return OK;
}//ListDelete_sq
- 顺序表在某位置上的删除和插入操作时间主要消耗在移动元素上。
- 假设 P i P_i Pi是顺序表L在第i个元素之前插入一个元素的概率,则在长度为n的线性链表L中插入一个元素需要移动的次数期望为 ∑ 1 n + 1 [ P i ∗ ( n − i + 1 ) ] ∑_1^{n+1} [Pi*(n-i+1)] ∑1n+1[Pi∗(n−i+1)]。
- 假设 Q i Q_i Qi是顺序表L删除第i个元素的概率,则在长度为n的L中删除一个元素需要移动的次数期望为 ∑ 1 n [ Q i ∗ ( n − i ) ] ∑_1^{n}[Qi*(n-i)] ∑1n[Qi∗(n−i)]。
- 不失一般性,若 P i 、 Q i Pi、Qi Pi、Qi是等概率的,则插入和删除分别平均移 n 2 、 n − 1 2 \frac{n}{2}、 \frac{n-1}{2} 2n、2n−1。则ListInsert_Sq和ListDelete_sq的时间复杂度为 O ( n ) O(n) O(n)。
// 函数指针:指向函数的指针;
// 指针函数:返回值是一个指针的函数;
int LocateElem_Sq(SqList L, ElemType e, Status (*compare)(ElemType,ElemType)){
//在顺序表L中查找与e满足compare()的元素的位序
//若找到,则返回对应位序,否则返回0
i = 1;
p = L.elem;
while((i<=L.length)&&!(compare(*p++,e))) i++;
if(i<=L.length) return i;
else return 0;
}//LocateElem_Sq
void MergeList_Sq(SqList La, SqList Lb, SqList &Lc){
//已知顺序表La、Lb的数据元素按值非递减有序排列
//归并后的顺序表Lc的数据元素也按值非递减有序排列
pa = La.elem;
pb = Lb.elem;
Lc.listsize = Lc.length = La.length + Lb.length;
pc = Lc.elem = (ElemType*)malloc(Lc.listsize * sizeof(ElemType));
if(!Lc.elem) exit(overflow);
pa_last = La.elem + La.length - 1;
pb_last = Lb.elem + Lb.length - 1;
while((pa<=pa_last)&&(pb<=pb_last)){
if(*pa <= *pb) *pc++ = *pa++;
else *pc++ = *pb++;
}
while(pa<=pa_last) *pc++ = *pa++;
while(pb<=pb_last) *pc++ = *pb++;
return OK;
}//MergeList_Sq
- 若将第一个while循环中的条件语句改为“switch…case…”语句,并当
*pa=*pb
的时候改为*pc++ = *pa++;*pb++;
由于集合A、B而言是值单增的,则该算法完成的操作和union()相同,但很明显时间复杂度不同。- 时间复杂度不同的原因:
- ① 由于La、Lb的值以单增有序排列,则对La中的每一个元素无需从La由表头到表尾进行全程搜索。
- ② 用Lc表示合并之后的“并集”,union()中的插入操作是通过“复制”实现的。
- 因此,由快速排序算法的时间复杂度是 O ( n l o g ( n ) ) O(nlog(n)) O(nlog(n)),则可知在进行集合合并相关的操作时,先要对集合对应的顺序表进行排序。
1.3 线性表的链式表示和实现
线性表的链式存储结构的特点是用一组任意的存储单元存储线性表中的数据元素。(这些存储单元可以是连续的,也可以是不连续的)
结点:数据元素的存储映像(由数据域+指针域组成)。
数据域:用于存储数据元素信息的域。
指针域:(对单链表而言)存储一个指示其直接后继的信息(即直接后继的地址)。
指针(链):指针域中存储的信息。
1.3.1 线性链表(单链表)
特点:链表的每个结点中只包含一个指针域。
头指针:指向链表中第一个结点(即第一个数据元素的映像)。
- 线性链表的存取必须从头指针开始进行,因此单链表是非随机存取的存储结构。由于线性链表的最后一个结点没有直接后继,因此最后一个结点的指针为NULL。
- 用线性链表表示线性表时,数据元素之间的逻辑关系是由结点中的指针指示的,因此,指针为数据元素之间的逻辑关系的映像。
// 由于单链表可由头指针唯一确定,在C中用结构指针描述
struct LS{
char name[20];
int num;
}L1,*p;
//L1是LS的别名,p=&L1,p是struct LS*类型,p指向L1的首地址,即p和(*p).name表示同一个内存空间,
//(*p).name的类型是char*。L1.name,(*p).name,p->name等价。
(1) 线性链表动态存储结构表示
//-----------单链表的动态存储结构-------------
typedef struct LNode{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
对于没有头结点的单链表,L是LinkList类型的变量,则L为该单链表的头指针。
L=NULL
表示空表。
对于有头结点的单链表,L是LinkList类型的变量,L->next=NULL
表示空表。
Status GetElem_L(LinkList L, int i, ElemType &e){
//L是带头结点的单链表的头指针
//当第i个元素存在时,用e返回其值且返回OK,否则返回ERROR
p = L->next;
j = 1;
while((j<i)&&p){ p = p->next; j++;}
if(!p||j>i) return ERROR;
e = p->data;
return OK;
}//GetElem_L
该算法的时间复杂度为 O ( n ) O(n) O(n)。
Status ListInsert_L(LinkList &L, int i, ElemType e){
//在带头结点的单链表的第i个位置之前插入元素e
p = L;
int j = 0;
while(p&&(j<i-1)){ p = p->next; j++;} //寻找指向第i-1位置的指针
// if(!p||(j>i-1)) return ERROR;
s = (LinkList)malloc(sizeof(LNode));
if(!s) exit(overflow);
s->data = e;
s->next = p->next;
p->next = s;
return OK;
}//ListInsert_L
该算法的时间复杂度为 O ( n ) O(n) O(n)。
Status ListDelete_L(LinkList &L, int i, ElemType &e){
//删除带头结点的单链表的第i个位置元素,并用e返回其值
p = L;
int j = 0;
while((p->next)&&(j<i-1)){p = p->next; j++;} //寻找指向第i-1位置的指针
// if(!(p->next)||(j>i-1)) return ERROR;
q = p->next;
e = q->data;
p->next = q->next;
free(q);
return OK;
}//ListDelete_L
该算法的时间复杂度为 O ( n ) O(n) O(n)。
void CreateList_L(LinkList &L, int n){
//逆位序输入n个元素的值,建立带有头结点的单链表L
L = (LinkList)malloc(sizeof(LNode));
L->next = NULL;
for(int i=n; i>=1; i--){
p = (LinkList)malloc(sizeof(LNode));
// if(!p){ClearList_L(L); exit(overflow);}
scanf(&p->data);
p->next = L->next;
L->next = p;
}
}//CreateList_L
显然易见,按逆位序建立的时间复杂度为 O ( n ) O(n) O(n),而按顺位序建立的时间复杂度为 O ( n 2 ) O(n^2) O(n2)。
void MergeList_L(LinkList &La, LinkList &Lb, LinkList &Lc){
//已知单链表La,Lb是按值不减有序排列
//归并La和Lb得单链表Lc,Lc也是按值不减有序排列
pa = La->next;
pb = Lb->next;
Lc = pc = La;
while(pa&&pb){
if((pa->data)<=(pb->data))){
pc->next = pa;
pc = pa;
pa = pa->next;
}
else{
pc->next = pb;
pc = pb;
pb = pb->next;
}
}
pc->next = pa?pa:pb;
free(pb);
}MergeList_L
该算法的时间复杂度为 O ( L i s t L e n g t h L ( L a ) + L i s t L e n g t h L ( L b ) ) O(ListLength_L(La)+ListLength_L(Lb)) O(ListLengthL(La)+ListLengthL(Lb))。
该算法与之前MergeList_Sq()的空间复杂度不同,因为该算法在归并两个链表时,不需建立新表的存储关系,只需将原来两个链表中结点之间的关系解除然后在重新按值非递减将所有结点链接成一个链表即可。
(2) 线性链表静态存储结构表示
//---------------线性链表的静态单链表的存储结构--------------------------
#define MAXSIZE 100
typedef struct{
ElemType data;
int cur;
}component,SLinkList[MAXSIZE];
- 定义了一个匿名结构体,component是其的别名,SLinkList是component类型的数组。
- 数组的一个分量表示一个结点,游标(指示器cur)代替指针指示结点在数组中的相对位置。数组的第零个分量可以看成是头结点,其指针域指示链表的第一个结点。这种存储结构需要预先分配一个较大的存储空间,但作为线性表的插入和删除操作无需移动元素,仅需修改指针,故仍具有链式存储结构的主要优点。
int GetElem_SL(SLinkList L, ElemType e){
//在静态链表L中查找值为e的第1个元素
//若找到,则返回对应位序,否则返回0
i = L[0].cur;
while(i&&(L[i].data!=e)){
i = L[i].cur;
}
return i;
}//GetElem_SL
void InitList_SL(SLinkList &space){
//将一维数组space的各分量链接成一个备用链表,头指针为space[0].cur
//“0”代表空指针
for(int i=0; i<MAXSIZE-1; i++){ space[i].cur = i+1;}
space[MAXSIZE-1].cur = 0;
}//InitList_SL
int Malloc_SL(SLinkList &space){
//若备用链表非空,则返回分配结点下标,否则返回0
i = space[0].cur;
if(space[0].cur) space[0].cur = space[i].cur;
return i;
}//Malloc_SL
void Free_SL(SLinkList &space, int k){
//将下标为k的空闲结点回收到备用链表
space[k].cur = space[0].cur;
space[0].cur = k;
}//Free_SL
void difference(SLinkList &space, int &S){
//依次输入A、B集合的元素,在一维数组space中建立集合(A-B)∪(B-A)的静态链表,S为其的头指针。
//假设备用空间足够大,space[0].cur为其头指针。
InitList_SL(space);
S = Malloc_SL(space);
r = S;
scanf(m,n); //m,n分别是A和B的元素个数
for(j=1; j<=m; j++){
i = Malloc_SL(space);
scanf(space[i].data);
space[r].cur = i;
r = i; //r指向当前S的最后一个结点,即(合并前、后)属于A的最后一个结点
}
space[r].cur = 0;
for(j=1; j<=n; j++){
scanf(b);
p = S;
k = space[S].cur;
while((space[k].data!=b)&&(space[r].cur!=k)){
p = k;
k = space[k].cur;
}
if(k == space[r].cur){
i = Malloc_SL(space);
space[i].data = b;
space[i].cur = space[r].cur;
space[r].cur = i;
}
else{
space[p].cur = space[k].cur;
Free_SL(space, k);
if(r == k) r = p;
}
}
}//difference
该算法的时间复杂度为 O ( m ∗ n ) O(m*n) O(m∗n)。
eg. 线性表 L a = ( c , b , e , g , f , d ) La=(c,b,e,g,f,d) La=(c,b,e,g,f,d)表示结合A,线性表 L b = ( a , b , n , f ) Lb=(a,b,n,f) Lb=(a,b,n,f)表示B, difference()求 ( A − B ) ∪ ( B − A ) (A-B)\cup(B-A) (A−B)∪(B−A),其中space静态单链表如前图 1.3.1-2所示。
1.3.2 循环链表
- 特点:表中的最后一个结点的指针域指向头结点,整个链表形成一个环。
- 循环链表的操作和线性链表的操作基本一致,不同在于算法中的循环条件由p或p->next非空,而是是否等于头指针;
- 但有时候,在循环链表设立尾指针而不设头指针,则可使某些操作简化。如在合并两个线性表时,只需将一个表的表尾和另一个表的表头的相连接即可,时间复杂度为 O ( 1 ) O(1) O(1)。
1.3.3 双向链表
特点:各结点中有两个指针域,一个指向直接后继,一个指向直接前驱。
//-----------------线性表的双向链表存储结构--------------------
typedef struct DuLNode{
ElemType data;
struct DuLNode *prior;
struct DuLNode *next;
}DuLNode,*DuLinkList;
(1) 双向循环链表
特点:
d->next->prior = d->prior->next = d
Status ListInsert_DuL(DuLinkList &L, int i, ElemType e){
//在带头结点的双向循环链表L中第i个位置之前插入元素e
//i的合法值为 1<=i<=表长+1
if(!GetElem_DuL(L,i)) return ERROR;
if(!(s = (DuLinkList)malloc(sizeof(DuLNode)))) return ERROR;
s->data = e;
p->prior->next = s;
s->prior = p->prior;
s->next = p;
p->prior = s;
return OK;
}//ListInsert_DuL
该算法的时间复杂度为 O ( n ) O(n) O(n);
Status ListDelete_DuL(DuLinkList &L, int i, ElemType &e){
//删除带头结点的双向循环链表L中第i个位置的元素
//i的合法值为1<=i<=表长,且用e返回该元素
if(!GetElem_DuL(L,i)) return ERROR;
e = p->data;
p->prior->next = p->next;
p->next->prior = p->prior;
free(p);
return OK;
}//ListDelete_DuL
该算法的时间复杂度为 O ( n ) O(n) O(n);
1.3.4 一般线性链表存储表示
typedef struct LNode{
ElemType data;
struct LNode *next;
}*Link,*Position;
typedef struct{
Link head,tail;
int len;
}LinkList;
Status MakeNode(Link &p, ElemType e);
//分配由p指向值为e的结点,并返回OK;若分配失败,返回ERROR;
void FreeNode(Link &p);
//释放p指向的结点
Status InitList(LinkList &L);
//构造一个空的线性链表L
Status DestroyList(LinkList &L);
//销毁线性链表L
Status ClearList(LinkList &L);
//将线性链表L置位空表,并释放原来链表的结点空间
Status InsFirst(Link h, Link s);
//已知h指向线性链表的头结点,将s指向的结点插入在第一个节点之前
Status DelFirst(Link h, Link &q);
//已知h指向线性链表的头结点,删除线性链表的第一个结点并返回q
Status Append(LinkList &L, Link s);
//将指针s所指的一串结点(彼此以指针相互链接)链接在线性链表的最后一个结点,并改变L的尾指针指向新链表的尾结点
Status Remove(LinkList &L, Link &q);
//删除线性链表的尾结点,并以q返回,并改变L的尾指针指向新的尾结点
Status InsBefore(LinkList &L, Link &p, Link s);
//已知p指向L中的一个结点,将s指向的结点插入在p所指的结点之前,并修改指针p指向新插入的结点
Status InsAfter(LinkList &L, Link &p, Link s);
//已知p指向L中的一个结点,将s指向的结点插入在p所指的结点之后,并修改指针p指向新插入的结点
Status SetCurElem(Link &p, ElemType e);
//已知p指向线性链表的一个结点,用e更新p所指结点的数据元素的值
ElemType GetCurElem(Link p);
//已知p指向线性链表的一个结点,返回p所指结点的数据元素的值
Status ListEmpty(LinkList L);
//若线性链表为空表,则返回True,否则返回False。
int ListLength(LinkList L);
//返回线性链表的元素个数
Position GetHead(LinkList L);
//返回线性链表头结点的位置
Position GetLast(LinkList L);
//返回线性链表最后一个结点的位置
Position PriorPos(LinkList L, Link &p);
//已知p指向线性链表L中的一个结点,返回p所指结点的直接前驱的位置,若无前驱返回NULL
Position NextPos(LinkList L, Link &p);
//已知p指向线性链表L中的一个结点,返回p所指结点的直接后继的位置,若无后继返回NULL
Status LocatePos(LinkList L, int i, Link &p);
//返回p指示线性链表L的第i个结点的位置并返回OK,i值不合法时返回ERROR
Position LocateElem(LinkList L, ElemType e, Status (*compare)(ElemType,ElemType));
//返回线性链表第一个与e符合compare()判定关系的元素位置,若不存在则返回NULL
Status ListTraverse(LinkList L, Status(*visit)());
//依次对L的每个元素进行visit,一旦visit失败则操作失败
Status ListInsert(LinkList &L, int i, ElemType e){
//在带头结点的单链表L中第i个位置之前插入元素e
if(!LocatePos(L,i-1,h)) return ERROR;
if(!MakeNode(s,e)) return ERROR;
InsFirst(h,s);
return OK;
}//ListInsert
Status MergeList(LinkList &La, LinkList &Lb, LinkList &Lc){
//已知单链表La,Lb是按值不减有序排列
//归并La和Lb得单链表Lc,Lc也是按值不减有序排列
if(!InitList(Lc)) return ERROR;
ha = GetHead(La);
hb = GetHead(Lb);
pa = NextPos(La,ha);
pb = NextPos(Lb,hb);
while(pa&&pb){
a = GetCurElem(pa);
b = GetCurElem(pb);
if((*compare)(a,b)<=0){
DelFirst(ha,q);
Append(Lc,q);
pb = NextPos(Lb,hb);
}
else{
DelFirst(hb,q);
Append(Lc,q);
pa = NextPos(La,ha);
}
}
if(pa) Append(Lc,pa);
else Append(Lc,pb);
FreeNode(ha);
FreeNode(hb);
return OK;
}//MergeList
1.4 一元多项式的表示及相加
顺序存储表示
链式存储表示
有序链表和线性链表的基本操作有两处不同:
① 是LocateElem()职能不同;② 是需增加按有序关系进行插入的操作
//Status LocateElem(LinkList L, ElemType e, Position &q, int (*compare)(ElemType,ElemType));
//若有序链表L中存在与e符合compare()值为0的元素,则q指向L中第一个值为e的结点,并返回True
//否则,q指示第一个与e满足compare()取值>0的元素的前驱,并返回False
Status OrderInsert(LinkList &L, ElemType e, int (*compare)(ElemType,ElemType));
//按有序判定函数compare将值为e的结点插入到L的适当位置
typedef struct{
float coef;
int expn;
}term, ElemType;
typedef LinkList polynomial;
//----------------基本操作的函数原型说明-------------
void CreatPolyn(polynomial &P, int m);
void DestroyPolyn(polynomial &P);
void PrintPolyn(polynomial P);
int PolynLength(polynomial P);
void AddPolyn(polynomial &Pa, polynomial &Pb);
void SubtractPolyn(polynomial &Pa, polynomial &Pb);
void MutiplyPolyn(polynomial &Pa, polynomial &Pb);
//--------------------算法描述-------------------------
int cmp(term a, term b){
return (a.expn>b.expn)?1:((a.expn < b.expn)?-1:0);
}//cmp
void CreatPolyn(polynomial &P, int m){
InitList(P);
h = GetHead(P);
e.coef = 0;
e.expn = -1;
SetCurElem(h,e);
for(i=1; i<=m; i++){
scanf(e.coef,e.expn);
if(!LocateElem(P,e,q,(*cmp)())){
if(!MakeNode(s,e)) InsFirst(q,s);
}
}
}//CreatPolyn
void AddPolyn(PolynLength &Pa, polynomial &Pb){
ha = GetHead(Pa);
hb = GetHead(Pb);
qa = NextPos(ha);
qb = NextPos(hb);
while(qa&&qb){
a = GetCurElem(qa);
b = GetCurElem(qb);
swith(*cmp(a,b)){
case -1:
ha = qa; qa = NextPos(Pa, qa); break;
case 0:
sum = a.coef + b.coef;
if(sum != 0.0){
SetCurElem(qa,sum);
ha = qa;
}
else{
DelFirst(ha,qa);
FreeNode(qa);
}
DelFirst(hb,qb);
FreeNode(qb);
qb = NextPos(Pb,hb);
qa = NextPos(Pa,ha);
break;
case 1:
DelFirst(hb,qb);
InsFirst(ha,qb);
qb = NextPos(Pb,hb);
ha = NextPos(Pa,ha);
break;
}
}
if(!ListEmpty(Pb)) Append(Pa,qb);
FreeNode(hb);
}//AddPolyn