《数据结构题集(C语言版)》第2章(线性表)习题自解答

说明:《数据结构题集(C语言版)》(严蔚敏等编著,清华大学出版社,旧版电子书封面为蓝灰色,简称《题集》)是《数据结构(C语言版)》(严蔚敏等编著,清华大学出版社,封面为紫色,下称“主书”)的配套书籍。《题集》的习题篇与主书相对应,分为12章。
题号后的带圈数字表示难度系数,难度级别从①至⑤逐渐加深。题号前有标注◆的题目是编者自认为值得向读者推荐的“好题”。(难度系数与“好题”均为《题集》编者标注,非本人标注)
部分算法使用了主书的配套代码中定义的数据类型和函数,在这些算法的头部省略了#include指令。
《题集》第1章为绪论,理论知识较多,本人也进行了自解答,不公开发布。本文是第2章(线性表)习题的部分自解答。后续章节不再进行自解答。本自解答在完成后参考了《题集》中的提示和答案、康建伟给出的自解答来进行订正,并经过简单测试运行。如发现错误,可留言指出。
2020年4月2日更新,2020年2-3月编写

◆2.12②

int ListCompare_Sq(SqList A,SqList B)
{//本算法比较顺序表A和B的大小
    int la=A.length,lb=B.length;
    int i=0,d=0;
    while(i<la&&i<lb&&d==0)
    {
        d=A.elem[i]-B.elem[i];
        i++;
    }
    if(d!=0) return d;
    else return la-lb;
}

2.15②

Status ListConnect(LinkList ha,LinkList hb,LinkList &hc){
//本程序将以hb为头结点的链表连接到以ha为头结点的链表之后,
//并用hc返回连接后链表的头结点,已知两个链表的长度分别为m和n
    LinkList p,q;//p指向短链表,q指向长链表
    if(m<n) {p=ha;q=hb;}
    else{p=hb;q=ha;}
    hc=p;
    while(p->next) p=p->next;
    p->next=q->next;
    free(q);
    return OK;
}

时间复杂度:O(min(m,n))

2.17②

注释中有标明本算法与主书P29算法2.9的不同之处。

Status ListInsert(LinkList &L,int i,ElemType e) // 算法2.9。不改变L
{ // 在无头结点的单链线性表L中第i个位置之前插入元素e
    int j=1;//主书:j=0
    LinkList p=L,s;
    while(p&&j<i-1) // 寻找第i-1个结点
    {
        p=p->next;
        j++;
    }
    if(!p L&&p==NULL||j>i-1&&i!=1) // 此条件不同,空表的L=NULL;i小于1或者大于表长(i=1时j>0)
        return ERROR;
	s=(LinkList)malloc(sizeof(LNode)); // 生成新结点
	if(!s) return OVERFLOW;
    s->data=e; // 插入L中
    if(i==1)//增加此段
    {
        s->next=p;//插在p的前面
        L=s;
    }
    else
    {
        s->next=p->next;
        p->next=s;
    }
    return OK;
}

注意:无头结点的单链表的InitList(LinkList &L)函数简化为一句话:L=NULL;

2.18②

注释中有标明本算法与主书P30算法2.10的不同之处。

Status ListDelete(LinkList L,int i,ElemType &e) // 算法2.10。不改变L
{ // 在无头结点的单链线性表L中,删除第i个元素,并由e返回其值
    int j=1;//主书:j=0
	LinkList p=L,q;
	if(!p) return ERROR;//此句新增,空表:出错
    while(p->next&&j<i-1) // 寻找第i个结点,并令p指向其前趋
    {
        p=p->next;
        j++;
    }
    if(!p->next||j>i-1&&i!=1) // 此句不同,删除位置不合理
    return ERROR;
    if(i==1)//此段新增
    {
        q=p;//首元结点无前驱
        L=p->next;
    }
    else
    {
        q=p->next; // 删除并释放结点
        p->next=q->next;
    }
    e=q->data;
    free(q);
    return OK;
}

◆2.19③

Status ListDelete(LinkList L,int mink,int maxk)
{//本算法删除单链表L中所有值大于mink且小于maxk的元素
    if(mink>maxk) return ERROR;
    LinkList p=L,q=p->next,r;
    while(q&&q->data<=mink)
    {
        p=q;
        q=q->next;
    }//使p指向删除段的前驱
    while(q&&q->data<maxk)
    {
        r=q;
        q=q->next;//使q指向删除段的后继
        free(r);
    }
	p->next=q;
	return OK;
}

2.20②

Status ListDelete(LinkList &L)
{//本算法删除递增有序的单链表L中所有值相同的多余元素
    LinkList p=L->next,q,r;
    while(p)//p指向删除段前驱
    {
        q=p->next;
        while(q&&q->data==p->data)
        {
            r=q;
            q=q->next;
            free(r);
        }//出循环时,q指向删除段后继
        p->next=q;
        p=p->next;
    }
    return OK;
}

时间复杂度:O(n)

◆2.21③

void Reverse(SqList &L)
{//本算法实现顺序表的就地逆置
    ElemType t;
    ElemType *p=L.elem,*q=p+L.length-1;
    while(p<q)
    {
        t=*p;
        *p=*q;
        *q=t;
        p++;
        q--;
    }
}

◆2.22③

对单链表实现就地逆置。
第一次写出的算法如下。

void Reverse(LinkList &L){
    if(!L->next) return;
    LinkList p=L->next,q=p->next,r;
    while(q){
        r=q->next;
        q->next=p;
        p=q;
        q=r;
    }
    L->next->next=NULL;
    L->next=p;
}

(答案提示)正确做法:将原链表中的头结点和第一个元素结点断开,先构成一个新的空表,然后将原链表中各结点依次插入新表的头部。

以下为根据此提示写出的算法。

void Reverse(LinkList L){
    LinkList p=L->next,q;
    L->next=NULL;
    while(p){
        q=p->next;
        p->next=L->next;
        L->next=p;
        p=q;
    }
}

◆2.24④

void ListMerge_OrderReverse(LinkList &A,LinkList &B,LinkList &C)
{//本算法将两个递增有序单链表B合并为递减有序单链表C
    LinkList pa=A->next,pb=B->next,q,p;
    C=A; C->next=NULL;//头插法注意头结点初始化
    while(pa&&pb)
    {
        if(pa->data<=pb->data)
        {
            q=pa->next;
            pa->next=C->next;
            C->next=pa;
            pa=q;
        }
        else
        {
            q=pb->next;
            pb->next=C->next;
            C->next=pb;
            pb=q;
        }
    }
    p=pa?pa:pb;
    while(p)
    {
        q=p->next;
        p->next=C->next;
        C->next=p;
        p=q;
    }
    free(B);
}

2.25④

假设以两个元素依值递增有序排列的线性表A和B分别表示两个集合(即同一表中的元素值各不相同),现要求另辟空间构成一个线性表C,其元素为A和B中元素的交集,且表C中的元素也依值有序递增排列。试对顺序表编写求C的算法。

void ListIntersection(SqList A,SqList B,SqList &C){
//本算法求两个递增有序顺序表A和B的交集C,C同样递增有序
//设指针pa和pb分别指向两表剩余部分顶端,每次循环比较二者的值,
//相等则插入表C,否则较小者后移。
    InitList(C);
    ElemType *pa=A.elem,*ma=pa+A.length,
             *pb=B.elem,*mb=pb+B.length;
    ElemType a,b;int i=1;
    while(pa<ma&&pb<mb){
        a=*pa,b=*pb;
        if(a!=b){
            if(a<b) pa++;
            else pb++;
        }
        else{
            ListInsert(C,i++,a);
            pa++;pb++;
        }
    }
}

2.26④

要求同2.25题。试对单链表编写求C的算法。

void ListIntersection(LinkList A,LinkList B,LinkList &C){
//本算法求两个递增有序单链表A和B的交集C,C同样递增有序
    InitList(C);
    LinkList pa=A->next,pb=B->next,pc=C,s;
    ElemType a,b;
    while(pa&&pb){
        a=pa->data,b=pb->data;
        if(a!=b){
            if(a<b) pa=pa->next;
            else pb=pb->next;
        }
        else{
            s=(LinkList)malloc(sizeof(LNode));
            s->data=a;
            pc->next=s;
            pc=s;
            pa=pa->next;
            pb=pb->next;
        }
    }
    pc->next=NULL;
}

◆2.27④

对2.25题的条件作以下两点修改,对顺序表重新编写求C的算法。
(1)假设在同一表(A或B)中可能存在值相同的元素,但要求新生成的表C中的元素值各不相同;
(2)利用A表空间存放表C。

void ListIntersection(SqList &A,SqList B){
//要求(2)实现:从A表首部开始存放表C。
//要求(1)实现:表C新元素生成后,后移pa和pb直到指向新元素
    ElemType *pa=A.elem,*ma=pa+A.length,
             *pb=B.elem,*mb=pb+B.length;
    ElemType a,b;int i=0;
    while(pa<ma&&pb<mb){
        a=*pa,b=*pb;
        if(a!=b){
            if(a<b) pa++;
            else pb++;
        }
        else{
            A.elem[i++]=a;
            do{pa++;}while(pa<ma&&*pa==a);
            do{pb++;}while(pa<mb&&*pb==b);
        }
    }
    A.length=i;
}

◆2.28④

对2.25题的条件作以下两点修改,对单链表重新编写求C的算法。
(1)假设在同一表(A或B)中可能存在值相同的元素,但要求新生成的表C中的元素值各不相同;
(2)利用原表(A表或B表)中的结点构造表C,并释放A表中的无用结点空间。

void ListIntersection(LinkList A,LinkList B,LinkList &C){
//设pc指向表C末端,pa去重在匹配前进行,pb去重在匹配后进行。
    LinkList pa=A->next,pb=B->next,pc=A,r;
    ElemType a,b;
    while(pa&&pb){
        a=pa->data,b=pb->data;
        if(a!=b){
            if(a<b) {
                r=pa;
                pa=pa->next;
                free(r);
            }
            else pb=pb->next;
        }
        else{
            pc->next=pa;
            pc=pc->next;
            pa=pa->next;
            do{pb=pb->next;}
            while(pb&&pb->data==b);
        }
    }
    pc->next=NULL;
    C=A;
}

◆2.29⑤

已知A,B和C为三个递增有序的线性表,现要求对A表进行如下操作:删去那些既在B表中出现又在C表中出现的元素。试对顺序表编写实现上述操作的算法,并分析你的算法的时间复杂度(注意:题中没有特别指明同一表中的元素值各不相同)。

void ListDelete(SqList &A,SqList B,SqList C){
//另设集合D=A∩B∩C,A=A-D(“-”表示求集合差的运算)
    SqList D=A;
    D.elem=(ElemType*)malloc(sizeof(ElemType)*D.listsize);
    memcpy(D.elem,A.elem,sizeof(ElemType)*D.listsize);
    ListIntersection(D,B);//2.27题的算法
    ListIntersection(D,C);
    ElemType *pa=A.elem,*ma=pa+A.length,
             *pd=D.elem,*md=pd+D.length;
    ElemType *p=pa;
    while(pa<ma){
        if(*pa!=*pd){
            *(p++)=*pa;
            pa++;
            continue;
        }
        else{
            do{pa++;}while(pa<ma&&*pa==*pd);
            pd++;if(pd==md) break;pb--;
			//B表比较完,应退回一位,因为A表可能未比较完
        }
    }
    A.length=p-A.elem;
}

从以上代码分离出求集合差A=A-B的算法:

void SetSub(SqList &A,SqList B){
//初始条件:B是A的子集
    ElemType *pa=A.elem,*ma=pa+A.length,
             *pb=B.elem,*mb=pb+B.length;
    ElemType *p=pa;
    while(pa<ma){
        if(*pa!=*pb){
            *(p++)=*pa;
            pa++;
            continue;
        }
        else{
            do{pa++;}while(pa<ma&&*pa==*pb);
            ElemType e=*pb;
            do{pb++;}while(pb<mb&&e==*pb);
            if(pb==mb) pb--;
        }
    }
    A.length=p-A.elem;
}

使用SetSub函数,并用表B存放表D,可将代码进一步简化。

void ListDelete(SqList &A,SqList B,SqList C){
    ListIntersection(B,C);//时间复杂度:O(B.length+C.length)
    ListIntersection(B,A); //时间复杂度:O(B.length+A.length)
    SetSub(A,B); //时间复杂度:O(A.length+B.length)
}

最坏情况下的时间复杂度:O(B.length)

◆2.30⑤

要求同2.29题。试对单链表编写算法,请释放A表中的无用结点空间。

void ListIntersection(LinkList A,LinkList B,LinkList &C){
//本算法求两个递增有序单链表A和B的交集C,C同样递增有序
    InitList(C);
    LinkList pa=A->next,pb=B->next,pc=C,s;
    ElemType a,b;
    while(pa&&pb){
        a=pa->data,b=pb->data;
        if(a!=b){
            if(a<b) pa=pa->next;
            else pb=pb->next;
        }
        else{
            s=(LinkList)malloc(sizeof(LNode));
            s->data=a;
            pc->next=s;
            pc=s;
            pa=pa->next;
            do{pb=pb->next;}
            while(pb&&pb->data==b);
        }
    }
    pc->next=NULL;
}

集合差算法链表版:

void SetSub(LinkList &A,LinkList B){
//初始条件:B是A的子集
    LinkList pa=A->next,pb=B->next;
    LinkList p=pa;
    while(pa){
        ElemType a=pa->data,b=pb->data;
        if(a!=b){
            p->data=a;
            p=p->next;
            pa=pa->next;
        }
        else{
            do{pa=pa->next;}while(pa&&pa->data==b);
            while(pb->next&&pb->data==b) pb=pb->next;
        }
	}
}
void ListDelete(LinkList &A,LinkList B,LinkList C){
    LinkList D;InitList(D);
    ListIntersection(B,C,D);//2.26题的算法,O(B.length+C.length)
    ListIntersection(D,A,D);//O(D.length+A.length)
    SetSub(A,D); //O(A.length+D.length)
}

最坏情况下的时间复杂度:O(A.length)

2.31②

假设某个单向循环链表的长度大于1,且表中既无头结点也无头指针。已知s为指向链表中某个结点的指针,试编写算法在链表中删除指针s所指结点的前驱结点。

void ListDelete_Prior(CLinkList s)
{
    s=s->prior;
    s->prior->next=s->next;
    s->next->prior=s->prior;
    free(s);
}

2.32②

已知有一个单向循环链表,其每个结点中含三个域:prior,data和next,其中data为数据域,next为指向后继结点的指针域,prior也为指针域,但它的值为空(NULL),试编写算法将此单向循环链表改为双向循环链表,即使prior成为指向前驱结点的指针域。

void PriorGenerate(DuLinkList &L)
{
    DuLinkList p=L,q=L->next;
    do{
        q->prior=p;
        p=q;
        q=q->next;
    }while(p!=L);
}

◆2.33③
已知由一个线性链表表示的线性表中含有三类字符的数据元素(如:字母字符、数字字符和其他字符),试编写算法将该线性链表分隔为三个循环链表,其中每个循环链表表示的线性表中均只含一类字符。

// 线性表的单循环链表存储结构(改写自"c2-4.h")
 typedef struct CLNode
 {
   ElemType data;
   CLNode *prior,*next;
 }CLNode,*CLinkList;
Status InitList(CLinkList &L){
//产生空的单循环链表L
    L=(CLinkList)malloc(sizeof(CLNode));
    if(!L) return OVERFLOW;
    L->next=L;
    return OK;
}
Status EndInsert(CLinkList &t,ElemType e){
//本函数在以t为尾指针的单循环链表末尾添加元素e
    CLinkList h=t->next;
    CLinkList s=(CLinkList)malloc(sizeof(CLNode));
    s->data=e;
    t->next=s;
    s->next=h;
    t=s;
    return OK;
}
void ListDivide(LinkList L,CLinkList &A,CLinkList &B,CLinkList &C){
//本算法将由三种字符组成的单链表分隔为三个各含一种字符的循环链表
    InitList(A);
    InitList(B);
    InitList(C);
    CLinkList a=A,b=B,c=C;
    int n=0;
    char c1,c2,c3;
    LinkList p=L->next;
    while(p){
        char ch=p->data;
        switch(n){
            case 0:n++;c1=ch;EndInsert(a,ch);
                   break;
            case 1:if(ch==c1) EndInsert(a,ch);
                   else{n++;c2=ch;EndInsert(b,ch);}
                   break;
            case 2:if(ch==c1) {EndInsert(a,ch);break;}
                   else if(ch==c2) {EndInsert(b,ch);break;}
                   else{n++;c3=ch;EndInsert(c,ch);
                       for(p=p->next;p;p=p->next)
                           switch(p->data){
                               case c1:EndInsert(a,c1);break;
                               case c2:EndInsert(b,c2);break;
                               case c3:EndInsert(c,c3);break;
                           }
					   }                   
        }
        p=p->next;
    }
}

2.34④

XorPointer XorP(XorPointer p, XorPointer q)
{//指针异或函数XorP返回指针p和q的异或(XOR)值
//因为指针变量不支持按位异或运算,需要强制类型转换为数值类型
//(其值为指针变量内存储的内存地址,长度与机器有关,C将其封装为size_t型)
    size_t x = (size_t)p;
    size_t y = (size_t)q;
    return (XorPointer)(x^y);
}
Status CreateList(XorLinkedList &L,char s[]){
//本算法建立一个2.34题所述的存储结构定义的双向链表L
//数据源为字符数组a
    const int N=15;//数据长度上限
    int n=strlen(s);
    if(n>N) return ERROR;
    XorPointer p[N];
    for(int i=0;i<n;i++){
        p[i]=(XorPointer)malloc(sizeof(XorNode));
        if(!p[i]) return OVERFLOW;
        p[i]->data=s[i];
    }
    if(n>=1){L.Left=p[0];L.Right=p[n-1];p[0]->LRPtr=NULL;}
    else L.Left=L.Right=NULL;
    if(n>=2) {p[n-1]->LRPtr=p[n-2];p[0]->LRPtr=p[1];}
    for(int i=1;i<n-1;i++)
        p[i]->LRPtr=XorP(p[i-1],p[i+1]);
    return OK;
}

先写出正向遍历的算法:

void PrintList(XorLinkedList L){
    XorPointer p=NULL,q=L.Left;
    if(!q) return;//空表
    putchar(q->data);//输出结点1
    XorPointer pq,r;
    for(pq=q->LRPtr;pq!=p;pq=q->LRPtr){
        //结点1->LRPtr=结点0○+结点2;
        //结点2->LRPtr=结点1○+结点3
        r=q;//保存结点1
        q=XorP(p,pq);//结点2= 结点0○+ (结点0○+结点2)
        putchar(q->data);//输出结点2
        p=r;//取出结点1
    }
}

可以证明,只需修改以上算法中的一条语句即可实现从右向左遍历,见注释。(约定“结点-x”为指向倒数第x个结点的指针)

void PrintList_Anti(XorLinkedList L){
    XorPointer p=NULL,q=L.Right;
    if(!q) return;//空表
    putchar(q->data);//输出结点-1
    XorPointer pq,r;
    for(pq=q->LRPtr;pq!=p;pq=q->LRPtr){
        //结点-1->LRPtr=结点0○+结点-2;
        //结点-2->LRPtr=结点-1○+结点-3
        r=q;//保存结点-1
        q=XorP(p,pq);//结点-2= 结点0○+ (结点0○+结点-2)
        putchar(q->data);//输出结点-2
        p=r;//取出结点-1
    }
}

将以上两个算法进行合并:

void PrintList(XorLinkedList L, Boolean forward){
//本算法以任意方向遍历2.34题所述的存储结构定义的双向链表L,
//forward指定遍历方向:true为从左向右,false为从右向左。
	XorPointer p=NULL, q=forward?L.Left:L.Right;
	if(!q) return;//空表
    putchar(q->data);//输出结点±1
    XorPointer pq,r;
    for(pq=q->LRPtr;pq!=p;pq=q->LRPtr){
        //结点1->LRPtr=结点0○+结点±2;
        //结点2->LRPtr=结点±1○+结点±3
        r=q;//保存结点±1
        q=XorP(p,pq);//结点±2= 结点0○+ (结点0○+结点±2)
        putchar(q->data);//输出结点±2
        p=r;//取出结点±1
    }
}

2.37④

设以带头结点的双向循环链表表示的线性表L=(a1,a2,…,an)。试写一个时间复杂度为O(n)的算法,将L改造为L=(a1,a3,…,an,…,a4,a2)。

void ListTransform(DuLinkList &L){
    DuLinkList p=L->next,q;
    while(true){
        if(p->next==L){
            p->next=p->prior;
            p=p->next;
            break;
        }
        else{
            q=p->next->next;
            if(q==L){
                p=p->next;
                break;
            }
            else{
                p->next=q;
                p=p->next;
            }
        }
    }//生成原奇数位序结点的next域
    while(p!=L){
        p->next=p->prior->prior;
        p=p->next;
    }//生成原偶数位序结点的next域
    for(p=L->next;p!=L;){
        q=p->next;
        q->prior=p;
        p=q;
    }//生成所有结点的prior域
}

◆2.38④

设有一个双向循环链表,每个结点中除有prior,data和next三个域外,还增设了一个访问频度域freq。在链表被起用之前,频度域freq的值均初始化为零,而每当对链表进行一次LOCATE(L,x)的操作后,被访问的结点(即元素值等于x的结点)的频度域freq的值便增1,同时调整链表中结点之间的次序,使其按访问频度非递增的次序顺序排列,以便始终保持被频繁访问的结点总是靠近表头结点。试编写符合上述要求的LOCATE操作的算法。

int LOCATE(DuLinkList &L,ElemType x){
//初始条件: 增加了频度域freq的双向循环链表L已存在,x为待查找元素的数值
//操作结果: 返回L中该元素的位序,若这样的数据元素不存在,则返回值为0
    DuLinkList p=L,q=L->next,r;
    //p指向上一“频度段”末尾,q指向当前“频度段”中某一结点
    int oldn=0,n=1;//oldn为p位序,n为q位序
    while(q!=L&&q->data!=x){
        r=q->next;
        if(r!=L&&r->freq!=q->freq) {oldn=n;p=q;}
        q=r;n++;
    }
    if(q==L) return 0;
    q->freq++;
    if(q->prior==L||q->prior->freq==q->freq) return n;
    q->prior->next=q->next;
    q->next->prior=q->prior;//删除结点q
    q->next=p->next;
    q->prior=p;
    p->next=q;
    q->next->prior=q;//结点p之后插入结点q
    //移动:删除插入二合一,无需新建结点
    return oldn+1;
}

◆2.39③

double Pn(SqPoly p,double x0){
// p.data[0].exp=0,从p.data[1]开始存储数据
    PolyTerm *e=p.data;
    int m=p.length;
    double sum=0,xei=1;
    for(int i=1;i<=m;i++){
        for(int j=e[i-1].exp;j<e[i].exp;j++)
            xei*=x0;//累乘一共进行了em次
        sum=sum+e[i].coef*xei;//累加一共进行了m次
    }
    return sum;
}

时间复杂度:O(em+m)

2.40③

void Sub(SqPoly p1,SqPoly p2,SqPoly &p3){
//本算法计算多项式减法P[3](x)=P[1](x)-P[2](x)
    p3.data=(PolyTerm *)malloc(sizeof(PolyTerm)*(p1.length+p2.length));
    p3.length=0;//对于不设listsize的顺序表派生数据类型,
    //其表长最好由实际情况决定
    PolyTerm *t1=p1.data,*t2=p2.data,*t3=p3.data;
    //t1,t2,t3分别为p1,p2,p3中的末尾游标
    PolyTerm *m1=t1+p1.length,m2=t2+p2.length;
    while(t1<m1&&t2<m2){
        int ei=t1->exp,ej=t2->exp;
        if(ej<ei) {*t3=*t2;t2++;t3++;}
        else{
            if(ej>ei){*t3=*t1;t3++;}
            else{
                t1->coef-=t2->coef;
                if(t1->coef!=0){*t3=*t1;t3++;}
                t2++;
            }
            t1++;
        }
    }
    while(t1<m1) {*t3=*t1;t1++;t3++;}
    while(t2<m2) {*t3=*t2;t3->exp/=(-1);t2++;t3++;}
    p3.length=t3-p3.data;
    p3.data=(PolyTerm *)realloc(p3.data,sizeof(PolyTerm)*(p3.length));
    //去除多余空间
}

时间复杂度:O(p1.length+p2.length)

◆2.41②

Status Differentiate(LinkedPoly &L){
    LinkedPoly p=L,q=p->next,r=q->next;
    while(r!=L){
        q->data.coef*=q->data.exp;
        q->data.exp--;
        q=p;r=q;r=r->next;
    }
    if(q->data.coef==0){
        free(q);
        p->next=L;
    }
    return OK;
}

2.42②

试编写算法,将一个用循环链表表示的稀疏多项式分解成两个多项式,使这两个多项式中各自仅含奇次项或偶次项,并要求利用原链表中的结点空间构成这两个链表。

Status ParitySeparation(LinkedPoly &L0,LinkedPoly &L1,LinkedPoly &L2){
//本算法将稀疏多项式L0分解成仅含奇次项的稀疏多项式L1和仅含偶次项
//的稀疏多项式L2
    L1=L0;
    if(InitPoly(L2)==OVERFLOW) return OVERFLOW;
    LinkedPoly p0=L1->next,p1=L1,p2=L2;
    while(p0!=L){
        if(p0->data.exp%2==1){
            p1->next=p0;p1=p1->next;
        }
        else{
            p2->next=p0;p2=p2->next;
        }
        p0=p0->next;
    }
    p1->next=L1;p2->next=L2;
    return OK;
}
  • 21
    点赞
  • 101
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
· 《数据结构(C语言) 严蔚敏主编》内容提要: 《数据结构》(C语言)是为“数据结构”课程编写的教材,也可作为学习数据结构及其算法的C程序设计的参考教材。本书的前半部分从抽象数据类型的角度讨论各种基本类型的数据结构及其应用;后半部分主要讨论查找和排序的各种实现方法及其综合分析比较。其内容和节编排与1992年4月出的《数据结构》(第二)基本一致,但在本书中更突出了抽象数据类型的概念。全书采用类C语言作为数据结构算法的描述语言。本书概念表述严谨,逻辑推理严密,语言精炼,用词达意。并有配套出的《数据结构题集)(C语言)。既便于教学,又便于自学。本书后附有光盘,光盘中含有可在DOS环境下运行的以类C语言描述的“数据结构算法动态模拟辅助教学软件,以及在Windows环境下运行的以类PASCAL或类C两种语言描述的“数据结构算法动态模拟辅助教学软件”。本书可作为计算机类专业或信息类相关专业的本科或专科教材,也可供从事计算机工程与应用工作的科技工作者参考。 · 《数据结构(C语言) 严蔚敏主编》图书目录: 第1 结论 1.1 什么是数据结构 1.2 基本概念和术语 1.3 抽象数据类型的表示与实现 1.4 算法算法分析 1.4.1 算法 1.4.2 算法设计的要求 1.4.3 算法效率的度量 1.4.4 算法的存储空间需求 第2 线性表 2.1 线性表的类型定义 2.2 线性表的顺序表示和实现 2.3 线性表的链式表示和实现 2.3.1 线性链表 2.3.2 循环链表 2.3.3 双向链表 2.4 一元多项式的表示及相加 第3 栈和队列 3.1 栈 3.1.1 抽象数据类型栈的定义 3.1.2 栈的表示和实现 3.2 栈的应用举例 3.2.1 数制转换 3.2.2 括号匹配的检验 3.2.3 行编辑程序 3.2.4 迷宫求解 3.2.5 表达式求值 3.3 栈与递归的实现 3.4 队列 3.4.1 抽象数据类型队列的定义 3.4.2 链队列--队列的链式表示和实现 3.4.3 循环队列--队列的顺序表示和实现 3.5 离散事件模拟 第4 串 4.1 串类型的定义 4.2 串的表示和实现 4.2.1 定长顺序存储表示 4.2.2 堆分配存储表示 4.2.3 串的块链存储表示 4.3 串的模式匹配算法 4.3.1 求子串位置的定位函数Index(S,T,pos) 4.3.2 模式匹配的一种改进算法 4.4 串操作应用举例 4.4.1 文本编辑 4.4.2 建立词索引表 第5 数组和广义表 5.1 数组的定义 5.2 数组的顺序表示和实现 5.3 矩阵的压缩存储 5.3.1 特殊矩阵 5.3.2 稀疏矩阵 5.4 广义表的定义 5.5 广义表的存储结构 5.6 m元多项式的表示 5.7 广义表的递归算法 5.7.1 求广义表的深度 5.7.2 复制广义表 5.7.3 建立广义表的存储结构 第6 树和二叉树 6.1 树的定义和基本术语 6.2 二叉树 6.2.1 二叉树的定义 6.2.2 二叉树的性质 6.2.3 二叉树的存储结构 6.3 遍历二叉树和线索二叉树 6.3.1 遍历二叉树 6.3.2 线索二叉树 6.4 树和森林 6.4.1 树的存储结构 6.4.2 森林与二叉树的转换 6.4.3 树和森林的遍历 6.5 树与等价问题 6.6 赫夫曼树及其应用 6.6.1 最优二叉树(赫夫曼树) 6.6.2 赫夫曼编码 6.7 回溯法与树的遍历 6.8 树的计数 第7 图 7.1 图的定义和术语 7.2 图的存储结构 7.2.1 数组表示法 7.2.2 邻接表 7.2.3 十字链表 7.2.4 邻接多重表 7.3 图的遍历 7.3.1 深度优先搜索 7.3.2 广度优先搜索 7.4 图的连通性问题 7.4.1 天向图的连通分量和生成树 7.4.2 有向图的强连通分量 7.4.3 最小生成树 7.4.4 关节点和重连通分量 7.5 有向无环图及其应用 7.5.1 拓扑排序 7.5.2 关键路径 7.6 最短路径 7.6.1 从某个源点到其余各项点的最短路径 7.6.2 每一对顶点之间的最短路径 第8 动态存储管理 8.1 概述 8.2 可利用空间表及分配方法 8.3 边界标识法 8.3.1 可利用空间表的结构 8.3.2 分配算法 8.3.3 回收算法 8.4 伙伴系统 8.4.1 可利用空间表的结构 8.4.2 分配算法 8.4.3 回收算法 8.5 无用单元收集 8.6 存储紧缩 第9 查找 9.1 静态查找表 9.1.1 顺序表的查找 9.1.2 有序表的查找 9.1.3 静态树表的查找 9.1.4 索引顺序表的查找 9.2 动态查找表 9.2.1 二叉排序树和平衡二
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值