第2章线性表 选择题 1.A|2.B3.C4.A C9.B|10.B,C|11 11.4B1.5c12.B13.c14.C15.C .A17.A18.A19.D20.C21.B 22.D23.C|24.B25.B26.A27.D 判断题 14. 16 部分答案解释如下 1、头结点并不“仅起”标识作用,并且使操作统一。另外,头结点数据域可写入链表长度, 或作监视哨。 4.两种存储结构各有优缺点,应根据实际情况选用,不能笼统说哪一个好。 7.集合中元素无逻辑关系 9.非空线性表第一个元素无前驱,最后一个元素无后继 13.线性表是逻辑结构,可以顺序存储,也可链式存储。 三.填空题 1.顺序 2.(n-1)/2 3. py->next=px->next: px->next=p 4 5.主要是使插入和删除等操作统一,在第一个元素之前插入元素和删除第一个结点不必 另作判断。另外,不论链表是否为空,链表指针不变 6.0(1),0(n 7.单链表,多重链表,(动态)链表,静态链表 8. f->next=p->next: f->prior=p: p->next->prior=f: p->next=f s, prior next 10.指针 11.物理上相邻指针 13.从任一结点出发都可访问到链表中每一个元素 14. u=p->next; p->next=u->next: free(u) 15. L->next->next==L 16. p->next! =null 7. L->next==l & L->prior==L 18. s->next=p->next: p->next=s 19.(1)IF pa=NIL THEN return(true) (2) pboNIL AND pa. data>=pb. data (3)return(inclusion(pa, pb)) (4)pb:=pb.next (5 return(false) 非递归算法 (1)pre: pb;(2)paONIL AND pb<>NIL AND pb. data)=pa. data (3)pa: =pa. nex nex (4)pb: =pre. next: pre: =pb pa: =pa. next: (5)IF pa=NIL THEN return (true) ELSE return(false) [注]:本题是在链表上求模式匹配问题。非递归算法中用指针pre指向主串中开始结点(初 始时为第一元素结点)。若主串与子串对应数据相等,两串工作指针pa和pb后移;否则
第 2 章 线性表 一.选择题 1.A 2.B 3.C 4.A 5.D 6.D 7.D 8.C 9.B 10.B,C 11.1I 11.2I 11.3E 11.4B 11.5C 12.B 13.C 14.C 15.C 16.A 17.A 18.A 19.D 20.C 21.B 22.D 23.C 24.B 25.B 26.A 27.D 二.判断题 1. × 2.√ 3. √ 4.× 5. × 6. × 7. × 8. × 9. × 10. × 11. × 12. × 13. × 14. √ 15. × 16. √ 部分答案解释如下。 1、 头结点并不“仅起”标识作用,并且使操作统一。另外,头结点数据域可写入链表长度, 或作监视哨。 4.两种存储结构各有优缺点,应根据实际情况选用,不能笼统说哪一个好。 7.集合中元素无逻辑关系。 9.非空线性表第一个元素无前驱,最后一个元素无后继。 13.线性表是逻辑结构,可以顺序存储,也可链式存储。 三.填空题 1.顺序 2.(n-1)/2 3.py->next=px->next; px->next=py 4 .n-i+1 5.主要是使插入和删除等操作统一,在第一个元素之前插入元素和删除第一个结点不必 另作判断。另外,不论链表是否为空,链表指针不变。 6.O(1),O(n) 7.单链表,多重链表,(动态)链表,静态链表 8.f->next=p->next; f->prior=p; p->next->prior=f; p->next=f; 9.p^.prior s^.prior^.next 10. 指针 11.物理上相邻 指针 12.4 2 13.从任一结点出发都可访问到链表中每一个元素。 14 . u=p->next; p->next=u->next; free(u); 15 . L->next->next==L 16.p->next!=null 17.L->next==L && L->prior==L 18.s->next=p->next;p->next=s; 19.(1) IF pa=NIL THEN return(true); (2) pb<>NIL AND pa^.data>=pb^.data (3) return(inclusion(pa,pb)); (4) pb:=pb^.next; (5) return(false); 非递归算法: (1)pre:=pb; (2) pa<>NIL AND pb<>NIL AND pb^.data>=pa^.data (3)pa:=pa^.next; pb:=pb->next; (4)pb:=pre^.next;pre:=pb;pa:=pa^.next;(5)IF pa=NIL THEN return(true) ELSE return(false); [注]:本题是在链表上求模式匹配问题。非递归算法中用指针 pre 指向主串中开始结点(初 始时为第一元素结点)。若主串与子串对应数据相等,两串工作指针 pa 和 pb 后移;否则
主串工作指针从pre的下一结点开始(这时pre又指向新的开始结点),子串工作指针从子 串第一元素开始,比较一直继续到循环条件失败。若pa为空,则匹配成功,返回true,否 则,返回 false VAR head: ptr B. new(p) C. p. data D.q^.next:=pE.q:=p(带头 结点) 21.(1)new(h);∥生成头结点,以便于操作。 (2)r" =g:(4)IF(q=NIL) THEN r.next 22. A: r. link. data>max and g. link. data<>max B: r: =r. link C: q. link D: q. link E: r. link F: r, link G:r:=s(或r:=r^.link) H: r: =r, link I: q. link: =s. link 23.(1)la (2)0 (3)jpre-next=q>next;q>next->pre=q>pre;∥先将q结点从链表上摘下 q.next:=p;q^.pre:=p^.pre;p^.pre->next:=q;p^.pre:=q;∥结点q插入 结点p前 (4)q^.freq=0∥链表中无值为x的结点,将新建结点插入到链表最后(头结点 )。 29.(1)a^.key:=’@’∥a的头结点用作监视哨,取不同于a链表中其它数据域的值 (2)b.key:=p^.key∥b的头结点起监视哨作用 (3)p:=p^.next∥找到a,b表中共同字母,a表指针后移 (4)0(m*n) 30.C部分:(1)p!=null ∥链表未到尾就一直作
主串工作指针从 pre 的下一结点开始(这时 pre 又指向新的开始结点),子串工作指针从子 串第一元素开始,比较一直继续到循环条件失败。若 pa 为空,则匹配成功,返回 true,否 则,返回 false。 20.A.VAR head:ptr B. new(p) C. p^.data:=k D. q^.next:=p E. q:=p(带头 结点) 21.(1)new(h);∥生成头结点,以便于操作。 (2)r^.next:=p; (3) r^.next:=q; (4) IF (q=NIL) THEN r^.next:=p; 22.A: r^.link^.data<>max AND q^.link^.data<>max B: r:=r^.link C: q^.link D: q^.link E: r^.link F: r^.link G: r:=s(或 r:= r^.link) H: r:=r^.link I: q^.link:=s^.link 23.(1)la (2)0 (3)jpre->next=q->next; q->next->pre=q->pre; ∥先将 q 结点从链表上摘下 q^.next:=p; q^.pre:=p^.pre; p^.pre->next:=q; p^.pre:=q; ∥结点 q 插入 结点 p 前 (4) q^.freq=0 ∥链表中无值为 x 的结点,将新建结点插入到链表最后(头结点 前)。 29.(1)a^.key:=’@’∥a 的头结点用作监视哨,取不同于 a 链表中其它数据域的值 (2)b^.key:=p^.key∥b 的头结点起监视哨作用 (3)p:=p^.next∥找到 a,b 表中共同字母,a 表指针后移 (4)0(m*n) 30. C 部分:(1)p!=null ∥链表未到尾就一直作
将当前结点作为头结点后的第一元素结点插入 31.(1)L=L->next;∥暂存后继 待逆置结点 (3)L=p ∥头指针仍为L 32.(1)p. next(>po (2)r: = p.next p, -r (2)NIL (3)x=x:(7)r (9)r (10NIL (11)NIL 34.(1)pa!=ha ∥或pa->exp!=-1 (2)pa->exp==0 ∥若指数为0,即本项为常数项 (3)q->next=pa->next∥删常数项 ∥取下一元素 pa->coef冰 p ∥指数项减1 (7)pa ∥前驱后移,或q>next 取下一元素 ∥q是工作指针p的前驱 (2)p.data>m∥p是工作指针 (3)r:=q ∥r记最大值的前驱, (4)q:=p ∥或q:=q.next (5)r.next:=q.next;∥或r.next:=r.next.next删最大值结点 36.(1)L->next=null∥置空链表,然后将原链表结点逐个插入到有序表中 2)p!=null ∥当链表尚未到尾,p为工作指针 (3)q!=null ∥查p结点在链表中的插入位置,这时q是工作指针 (4)p->next=r->next∥将p结点链入链表中 (5)r->next=p ∥r是q的前驱,u是下个待插入结点的指针 37.程序(a) PASCAL部分(编者略) 程序(b)C部分 (1)(A!=null&&B!=nul)∥两均未空时循环 (2)A-> element==B-> element∥两表中相等元素不作结果元素 (3)B=B->link ∥向后移动B表指针 (4)A!=null ∥将A表剩余部分放入结果表中 (5)last->link=null ∥置链表尾 四 应用题 1.(1)选链式存储结构。它可动态申请内存空间,不受表长度(即表中元素个数)的 影响,插入、删 除时间复杂度为0(1)。 (2)选顺序存储结构。顺序表可以随机存取,时间复杂度为0(1)。 2.链式存储结构一般说克服了顺序存储结构的三个弱点。首先,插入、删除不需移动 元素,只修改指针,时间复杂度为0(1);其次,不需要预先分配空间,可根据需要动态申 请空间:其三,表容量只受可用内存空间的限制。其缺点是因为指针增加了空间开销,当空 间不允许时,就不能克服顺序存储的缺点
(2)q ∥将当前结点作为头结点后的第一元素结点插入 31. (1)L=L->next; ∥暂存后继 (2)q=L; ∥待逆置结点 (3)L=p; ∥头指针仍为 L 32. (1) p^.next<>p0 (2)r:= p^.next (3) p^.next:= q0; (4) q0:= p; (5) p:=r 33. (1)r (2)NIL (3)x=x; (7)r (8)p (9)r (10)NIL (11)NIL 34.(1)pa!=ha ∥或 pa->exp!=-1 (2)pa->exp==0 ∥若指数为 0,即本项为常数项 (3)q->next=pa->next ∥删常数项 (4)q->next ∥取下一元素 (5)=pa->coef*pa->exp (6)-- ∥指数项减 1 (7)pa ∥前驱后移,或 q->next (8)pa->next ∥取下一元素 35.(1)q:=p; ∥q 是工作指针 p 的前驱 (2)p^.data>m ∥p 是工作指针 (3)r:=q; ∥r 记最大值的前驱, (4)q:=p; ∥或 q:=q^.next; (5)r^.next:=q^.next; ∥或 r^.next:=r^.next^.next 删最大值结点 36.(1)L->next=null ∥置空链表,然后将原链表结点逐个插入到有序表中 (2)p!=null ∥当链表尚未到尾,p 为工作指针 (3)q!=null ∥查 p 结点在链表中的插入位置,这时 q 是工作指针。 (4)p->next=r->next ∥将 p 结点链入链表中 (5)r->next=p ∥r 是 q 的前驱,u 是下个待插入结点的指针。 37.程序(a) PASCAL 部分(编者略) 程序(b) C 部分 (1)(A!=null && B!=null) ∥两均未空时循环 (2)A->element==B->element ∥两表中相等元素不作结果元素 (3)B=B->link ∥向后移动 B 表指针 (4)A!=null ∥将 A 表剩余部分放入结果表中 (5)last->link=null ∥置链表尾 四、 应用题 1.(1)选链式存储结构。它可动态申请内存空间,不受表长度(即表中元素个数)的 影响,插入、删 除时间复杂度为 O(1)。 (2)选顺序存储结构。顺序表可以随机存取,时间复杂度为 O(1)。 2.链式存储结构一般说克服了顺序存储结构的三个弱点。首先,插入、删除不需移动 元素,只修改指针,时间复杂度为 O(1);其次,不需要预先分配空间,可根据需要动态申 请空间;其三,表容量只受可用内存空间的限制。其缺点是因为指针增加了空间开销,当空 间不允许时,就不能克服顺序存储的缺点
3.采用链式存储结构,它根据实际需要申请内存空间,而当不需要时又可将不用结点 空间返还给系统。在链式存储结构中插入和删除操作不需要移动元素 4.线性表栈队列串 顺序存储结构和链式存储结构 顺序存储结构的定义是 c0 NST maxlen=线性表可能达到的最大长度; TYPE sqlisttp=RECORD elem: ARRAY[l. maxlen] OF ElemType last: 0. maxlen 链式存储结构的定义是: TYPE pointer= f nodetype nodetype=RECORD data: ElemType next: pointer: linklisttp=pointe 5顺序映射时,a与aH的物理位置相邻;链表表示时a1与a1的物理位置不要求相邻 6.在线性表的链式存储结构中,头指针指链表的指针,若链表有头结点则是链表的头 结点的指针,头指针具有标识作用,故常用头指针冠以链表的名字。头结点是为了操作的统 、方便而设立的,放在第一元素结点之前,其数据域一般无意义(当然有些情况下也可存 放链表的长度、用做监视哨等等),有头结点后,对在第一元素结点前插入结点和删除第 结点,其操作与对其它结点的操作统一了。而且无论链表是否为空,头指针均不为空。首元 结点也就是第一元素结点,它是头结点后边的第一个结点 7.见上题6 8.(1)将next域变为两个域:pre和next,其值域均为0. maxsize。初始化时,头结 点(下标为0的元素)其next域值为1,其pre域值为n(设n是元素个数,且nnext: p->next=q->next: free(g) 13.设单链表的头结点的头指针为head,且pre=head; while(pre->next!=p)pre=pre->next s->next=p: pre->next=s 14.设单链表带头结点,工作指针p初始化为p=H-next; (1)while(p!=null & p->data!=X)p=p->next if(p==null) return(nul1);∥查找失败 1 se return(p);∥查找成功
3.采用链式存储结构,它根据实际需要申请内存空间,而当不需要时又可将不用结点 空间返还给系统。在链式存储结构中插入和删除操作不需要移动元素。 4.线性表 栈 队列 串 顺序存储结构和链式存储结构。 顺序存储结构的定义是: CONST maxlen=线性表可能达到的最大长度; TYPE sqlisttp=RECORD elem:ARRAY[1..maxlen] OF ElemType; last:0..maxlen; END; 链式存储结构的定义是: TYPE pointer=↑nodetype; nodetype=RECORD data:ElemType; next:pointer; END; linklisttp=pointer; 5.顺序映射时,ai与 ai+1的物理位置相邻;链表表示时 ai与 ai+1的物理位置不要求相邻。 6.在线性表的链式存储结构中,头指针指链表的指针,若链表有头结点则是链表的头 结点的指针,头指针具有标识作用,故常用头指针冠以链表的名字。头结点是为了操作的统 一、方便而设立的,放在第一元素结点之前,其数据域一般无意义(当然有些情况下也可存 放链表的长度、用做监视哨等等),有头结点后,对在第一元素结点前插入结点和删除第一 结点,其操作与对其它结点的操作统一了。而且无论链表是否为空,头指针均不为空。首元 结点也就是第一元素结点,它是头结点后边的第一个结点。 7.见上题 6。 8.(1)将 next 域变为两个域: pre 和 next,其值域均为 0..maxsize。初始化时,头结 点(下标为 0 的元素)其 next 域值为 1,其 pre 域值为 n(设 n 是元素个数,且 nnext; p->next=q->next; free(q); 13. 设单链表的头结点的头指针为 head,且 pre=head; while(pre->next!=p) pre=pre->next; s->next=p; pre->next=s; 14.设单链表带头结点,工作指针 p 初始化为 p=H->next; (1) while(p!=null && p->data!=X) p=p->next; if(p= =null) return(null);∥查找失败 else return(p);∥查找成功
2)while(p!=null & p->datanext f(p==null|lp->data>x) return(nu11);∥查找失败 (p) (3)while! =null & p->data)X)p=p->next if(p=nul1|p>datapre=p->pre: s->next=p: p->pre->next=s: p->pre=s: 20.(A)f1 prior=q-> prior;∥将q结点摘下,以便插入到适当位置 (2)p->next-> prior=q;∥(2)(3)将q结点插入 (3)p->n (4)r=r->next;或r=q->next;∥后移指针,再将新结点插入到适当位置 算法设计题 1.[题目分析]因为两链表已按元素值递增次序排列,将其合并时,均从第一个结点起 进行比较,将小的链入链表中,同时后移链表工作指针。该问题要求结果链表按元素值递减 次序排列。故在合并的同时,将链表结点逆置
(2) while(p!=null && p->datanext; if(p==null || p->data>X) return(null);∥查找失败 else return(p); (3) while(p!=null && p->data>X) p=p->next; if(p==null || p->datapre=p->pre; s->next=p; p->pre->next=s; p->pre=s; 20.(A) f1<>NIL 并且 f2<>NIL (B) f1↑.data prior=q->prior;∥将 q 结点摘下,以便插入到适当位置。 (2)p->next->prior=q;∥(2)(3)将 q 结点插入 (3)p->next=q; (4)r=r->next;或 r=q->next;∥后移指针,再将新结点插入到适当位置。 五、 算法设计题 1.[题目分析]因为两链表已按元素值递增次序排列,将其合并时,均从第一个结点起 进行比较,将小的链入链表中,同时后移链表工作指针。该问题要求结果链表按元素值递减 次序排列。故在合并的同时,将链表结点逆置
LinkedList Union (LinkedList la, lb) ∥la,lb分别是带头结点的两个单链表的头指针,链表中的元素值按递增序排列,本算法 将两链表合并成一个按元素值递减次序排列的单链表 (pa=1a->next;pb=1b->next;∥pa,pb分别是链表la和1b的工作指针 la->next=null ∥1a作结果链表的头指针,先将结果链表初始化为 Whie(pa!=null&&pb!=nu1)∥当两链表均不为空时作 if(pa->datadata) i r=pa->next ∥将pa的后继结点暂存于r pa->next=1a->next;∥将pa结点链于结果表中,同时逆置。 Ia->next=pa ∥恢复pa为当前待比较结点。 else r=pb->next;∥将pb的后继结点暂存于r pb->next=1a->next;∥将pb结点链于结果表中,同时逆置 pb=r;∥恢复pb为当前待比较结点 while(pa!=null)∥将la表的剩余部分链入结果表,并逆置。 [r=pa>next: pa->next=la->next: la->next [r=pb->next: pb->next=la->next: la->next=pb; pb=r }∥算法 Union结束 [算法讨论]上面两链表均不为空的表达式也可简写为 while(pa&kpb),两递增有序表 合并成递减有序表时,上述算法是边合并边逆置。也可先合并完,再作链表逆置。后者不如 前者优化。算法中最后两个 while语句,不可能执行两个,只能二者取一,即哪个表尚未到 尾,就将其逆置到结果表中,即将剩余结点依次前插入到结果表的头结点后面。 与本题类似的其它题解答如下: (1)[问题分析]与上题类似,不同之处在于:一是链表无头结点,为处理方便,给 加上头结点,处理结束再删除之;二是数据相同的结点,不合并到结果链表中;三是hb链 表不能被破坏,即将hb的结点合并到结果链表时,要生成新结点。 LinkedList Union(LinkedList ha, hb) ∥ha和hb是两个无头结点的数据域值递增有序的单链表,本算法将hb中并不出现在ha 中的数据合并到ha中,合并中不能破坏hb链表。 (LinkedList la a=(LinkedList)malloc(sizeof (LNode)) la->next=ha;∥申请头结点,以便操作。 ∥pa是ha链表的工作指针 ∥pb是hb链表的工作指针 pre=la ∥pre指向当前待合并结点的前驱。 while(pa&&pb) if(pa-datadata)∥处理ha中数据 Ipre->next=pa: pre=pa; pa=pa-next: K
LinkedList Union(LinkedList la,lb) ∥la,lb 分别是带头结点的两个单链表的头指针,链表中的元素值按递增序排列,本算法 将两链表合并成一个按元素值递减次序排列的单链表。 { pa=la->next; pb=lb->next;∥pa,pb 分别是链表 la 和 lb 的工作指针 la->next=null; ∥la 作结果链表的头指针,先将结果链表初始化为 空。 while(pa!=null && pb!=null) ∥当两链表均不为空时作 if(pa->datadata) { r=pa->next; ∥将 pa 的后继结点暂存于 r。 pa->next=la->next; ∥将 pa 结点链于结果表中,同时逆置。 la->next=pa; pa=r; ∥恢复 pa 为当前待比较结点。 } else {r=pb->next;∥ 将 pb 的后继结点暂存于 r。 pb->next=la->next; ∥将 pb 结点链于结果表中,同时逆置。 la->next=pb; pb=r; ∥恢复 pb 为当前待比较结点。 } while(pa!=null) ∥将 la 表的剩余部分链入结果表,并逆置。 {r=pa->next; pa->next=la->next; la->next=pa; pa=r; } while(pb!=null) {r=pb->next; pb->next=la->next; la->next=pb; pb=r; } }∥算法 Union 结束。 [算法讨论]上面两链表均不为空的表达式也可简写为 while(pa&&pb),两递增有序表 合并成递减有序表时,上述算法是边合并边逆置。也可先合并完,再作链表逆置。后者不如 前者优化。算法中最后两个 while 语句,不可能执行两个,只能二者取一,即哪个表尚未到 尾,就将其逆置到结果表中,即将剩余结点依次前插入到结果表的头结点后面。 与本题类似的其它题解答如下: (1)[问题分析]与上题类似,不同之处在于:一是链表无头结点,为处理方便,给 加上头结点,处理结束再删除之;二是数据相同的结点,不合并到结果链表中;三是 hb 链 表不能被破坏,即将 hb 的结点合并到结果链表时,要生成新结点。 LinkedList Union(LinkedList ha, hb) ∥ha 和 hb 是两个无头结点的数据域值递增有序的单链表,本算法将 hb 中并不出现在 ha 中的数据合并到 ha 中,合并中不能破坏 hb 链表。 {LinkedList la; la=(LinkedList)malloc(sizeof(LNode)); la->next=ha;∥申请头结点,以便操作。 pa=ha; ∥pa 是 ha 链表的工作指针 pb=hb; ∥pb 是 hb 链表的工作指针 pre=la; ∥pre 指向当前待合并结点的前驱。 while(pa&&pb) if(pa->datadata)∥处理 ha 中数据 {pre->next=pa;pre=pa;pa=pa->next;}
else if(pa->data>pb->data)∥处理hb中数据 r=( Linkedlist) malloc( sizeof( L Node);∥/申请空间 r->data=pb->data; pre->next=r pre=r;∥将新结点链入结果链表 pb=pb->next;∥hb链表中工作指针后移 else∥/处理pa->data=pb->dat ipre->next=pa: pre=pa pa=pa->next;∥两结点数据相等时,只将ha的数据链入。 pb=pb->next;∥不要hb的相等数据 if(pa!=null)pre->next=pa;∥将两链表中剩余部分链入结果链表 free(la);∥释放头结点.ha,hb指针未被破坏 }∥算法nion结束 2)本题与上面两题类似,要求结果指针为lc,其核心语句段如下: pa=la->next: pb=hb->next Ic=(LinkedList )malloc(sizeof(LNode)) pc=lc;∥pc是结果链表中当前结点的前驱 while(pa&&pb) if(pa->datadata) Ipc->next=pa: pc=pa; pa=pa->next: I else [pc->next=pb; pc=pb; pb=pb->next: 1 if(pa)pc->next=pa; else pc->next=pb free(la);free(lb);∥释放原来两链表的头结点。 算法时间复杂度为0(m+n),其中m和n分别为链表1a和1b的长度。 2.[题目分析]本组题有6个,本质上都是链表的合并操作,合并中有各种条件。与前 组题不同的是,叙述上是用线性表代表集合,而操作则是求集合的并、交、差(AUB,A ∩B,A-B)等。 本题与上面1.(2)基本相同,不同之处1.(2)中链表是“非递减有序”,(可能包含 相等元素),本题是元素“递增有序”(不准有相同元素)。因此两表中合并时,如有元素值 相等元素,则应删掉一个。 LinkedList Union (LinkedList ha, hb) ∥线性表A和B代表两个集合,以链式存储结构存储,元素递增有序。ha和hb分别 是其链表的头指针。本算法求A和B的并集AUB,仍用线性表表示,结果链表元 素也是递增有序。 pa=ha->next;pb=hb->next;∥设工作指针pa和pb pc=ha;∥pc为结果链表当前结点的前驱指针 while(pa&&pb) if(pa->datadata) (pc->next=pa: pc=pa; pa=pa->next: I lse if(pa->data>pb->data) Ipc->next=pb; pc=pb; pb=pb->next: I else∥处理pa-data=pb->data
else if(pa->data>pb->data)∥处理 hb 中数据。 {r=(LinkedList)malloc(sizeof(LNode));∥申请空间 r->data=pb->data; pre->next=r; pre=r;∥将新结点链入结果链表。 pb=pb->next;∥hb 链表中工作指针后移。 } else∥处理 pa->data=pb->data; {pre->next=pa; pre=pa; pa=pa->next;∥两结点数据相等时,只将 ha 的数据链入。 pb=pb->next;∥不要 hb 的相等数据 } if(pa!=null)pre->next=pa;∥将两链表中剩余部分链入结果链表。 else pre->next=pb; free(la);∥释放头结点.ha,hb 指针未被破坏。 }∥算法 nion 结束。 (2)本题与上面两题类似,要求结果指针为 lc,其核心语句段如下: pa=la->next;pb=hb->next; lc=(LinkedList )malloc(sizeof(LNode)); pc=lc;∥pc 是结果链表中当前结点的前驱 while(pa&&pb) if(pa->datadata) {pc->next=pa;pc=pa;pa=pa->next;} else {pc->next=pb;pc=pb;pb=pb->next;} if(pa)pc->next=pa; else pc->next=pb; free(la);free(lb);∥释放原来两链表的头结点。 算法时间复杂度为 O(m+n),其中 m 和 n 分别为链表 la 和 lb 的长度。 2.[题目分析]本组题有 6 个,本质上都是链表的合并操作,合并中有各种条件。与前 组题不同的是,叙述上是用线性表代表集合,而操作则是求集合的并、交、差(A∪B,A ∩B,A-B)等。 本题与上面 1.(2)基本相同,不同之处 1.(2)中链表是“非递减有序”,(可能包含 相等元素),本题是元素“递增有序”(不准有相同元素)。因此两表中合并时,如有元素值 相等元素,则应删掉一个。 LinkedList Union(LinkedList ha,hb) ∥线性表 A 和 B 代表两个集合,以链式存储结构存储,元素递增有序。ha 和 hb 分别 是其链表的头指针。本算法求 A 和 B 的并集 A∪B,仍用线性表表示,结果链表元 素也是递增有序。 { pa=ha->next;pb=hb->next;∥设工作指针 pa 和 pb。 pc=ha;∥pc 为结果链表当前结点的前驱指针。 while(pa&&pb) if(pa->datadata) {pc->next=pa;pc=pa;pa=pa->next;} else if(pa->data>pb->data) {pc->next=pb;pc=pb;pb=pb->next;} else∥处理 pa->data=pb->data
Ipc->next=pa: pc=pa: pa=pa->next: >next: free(u): h if(pa)pc->next=pa;∥若ha表未空,则链入结果表 else pc->next=pb;∥若hb表未空,则链入结果表。 free(hb);∥释放hb头结点 return(ha) }∥算法 Union结束 与本题类似的其它几个题解答如下 (1)解答完全同上2。 (2)本题是求交集,即只有同时出现在两集合中的元素才出现在结果表中。其核心语句 段如下: pa=la->next;pb=1b->next;∥设工作指针pa和pb; pc=la;∥结果表中当前合并结点的前驱的指针。 if(pa->data==pb->data)∥交集并入结果表中 i pc->next=pa: pc=pa: pa=pa->next u=pb: pb=pb->next; free(u): 1 lse if(pa->datapb->data)fu u);} free(u): I whie(pa){u=pa;pa=pa->next;free(u);}∥释放结点空间 while(pb){u=pb;pb=pb->next;free(u);}∥释放结点空间 pc->next=nu1l;∥置链表尾标记 free(b);∥注:本算法中也可对B表不作释放空间的处理 (3)本题基本与(2)相同,但要求无重复元素,故在算法中,待合并结点数据要与其前 驱比较,只有在与前驱数据不同时才并入链表。其核心语句段如下。 pa=L1-next;pb=L2->next;∥pa、pb是两链表的工作指针 pc=L1;∥L1作结果链表的头指针 while(pa&&pl f(pa->datadata){u=pa;pa=pa->next;free(u);}∥删除L1表多余元素 else if(pa->data>pb->data)pb=pb-next;∥pb指针后移 else∥处理交集元素 {if(pc=L1){pc-next=pa;pc=pa;pa=pa->next;}∥处理第一个相等的元 else if(pc-data=pa->data){u=pa;pa=pa->next;free(u);}∥重复元 素不进入L1表。 lse{pc->next=pa;pc=pa;pa=pa->next;}∥交集元素并入结果表 ∥ while while(pa){u=pa;pa=pa->next;free(u);}∥删L1表剩余元素 pc->next=null;∥置结果链表尾 注:本算法中对L2表未作释放空间的处理 (4)本题与上面(3)算法相同,只是结果表要另辟空间。 (5)[题目分析]本题首先求B和C的交集,即求B和C中共有元素,再与A求并集,同 时删除重复元素,以保持结果A递增。 LinkedList union (LinkedList A, B, C)
{pc->next=pa;pc=pa;pa=pa->next; u=pb;pb=pb->next;free(u);} if(pa) pc->next=pa;∥ 若 ha 表未空,则链入结果表。 else pc->next=pb;∥若 hb 表未空,则链入结果表。 free(hb); ∥释放 hb 头结点 return(ha); }∥算法 Union 结束。 与本题类似的其它几个题解答如下: (1) 解答完全同上 2。 (2) 本题是求交集,即只有同时出现在两集合中的元素才出现在结果表中。其核心语句 段如下: pa=la->next;pb=lb->next;∥设工作指针 pa 和 pb; pc=la;∥结果表中当前合并结点的前驱的指针。 while(pa&&pb) if(pa->data==pb->data)∥交集并入结果表中。 { pc->next=pa;pc=pa;pa=pa->next; u=pb;pb=pb->next;free(u);} else if(pa->datadata) {u=pa;pa=pa->next;free(u);} else {u=pb; pb=pb->next; free(u);} while(pa){ u=pa; pa=pa->next; free(u);}∥ 释放结点空间 while(pb) {u=pb; pb=pb->next; free(u);}∥释放结点空间 pc->next=null;∥置链表尾标记。 free(lb); ∥注: 本算法中也可对 B 表不作释放空间的处理 (3)本题基本与(2)相同,但要求无重复元素,故在算法中,待合并结点数据要与其前 驱比较,只有在与前驱数据不同时才并入链表。其核心语句段如下。 pa=L1->next;pb=L2->next;∥pa、pb 是两链表的工作指针。 pc=L1;∥L1 作结果链表的头指针。 while(pa&&pb) if(pa->datadata) {u=pa;pa=pa->next;free(u);}∥删除 L1 表多余元素 else if (pa->data>pb->data) pb=pb->next; ∥pb 指针后移 else ∥处理交集元素 {if(pc==L1) {pc->next=pa;pc=pa;pa=pa->next;} ∥处理第一个相等的元 素。 else if(pc->data==pa->data){ u=pa;pa=pa->next;free(u);} ∥重复元 素不进入 L1 表。 else{ pc->next=pa;pc=pa;pa=pa->next;} ∥交集元素并入结果表。 } ∥while while(pa) {u=pa;pa=pa->next;free(u);} ∥ 删 L1 表剩余元素 pc->next=null; ∥置结果链表尾。 注: 本算法中对 L2 表未作释放空间的处理。 (4) 本题与上面(3)算法相同,只是结果表要另辟空间。 (5) [题目分析]本题首先求 B 和 C 的交集,即求 B 和 C 中共有元素,再与 A 求并集,同 时删除重复元素,以保持结果 A 递增。 LinkedList union(LinkedList A,B,C)
∥A,B和C均是带头结点的递增有序的单链表,本算法实现A=AU(B∩C),使求解结 构保持递增有序 pa=A->next;pb=B->next;pc=C->next;∥设置三个工作指针 pre=A;∥pre指向结果链表中当前待合并结点的前驱。 if(pa->data datal lpa->datadatadata)pb=pb->next else if (pb->data)pc->data)pc=pc->next else break;∥找到B表和C表的共同元素就退出 while循环 if(pb&&pc)∥因共同元素而非B表或C表空而退出上面 while循环。 if(pa->data>pb->data)∥A表当前元素值大于B表和C表的公共元素,先将B 表元素链入 pre->next=pb;pe=pb;pb=pb->next;pc=pc->next;}∥B,C公共元素为结果 表第一元素。 }∥结東了结果表中第一元素的确定 while(pa&&pb&& Iwhile(pb&&pc) if(pb->datadata) pb=pb->next else if(pb->data>pc->data)pc=pc->next else break;∥B表和C表有公共元素。 if(pb&&pc) while(pa&&pa->datadata)∥先将A中小于B,C公共元素部分链入。 (pre->next=pa pre=pa; pa=pa->next; 1 if(pre->data!=pb->data)pre->next=pb; pre=pb; pb=pb->next: pc=pc->next: K ese{pb=pb->next;pc=pc->next;}∥若A中已有B,C公共元素,则不再存 入结果表 }∥ while(pa&pb&pc) if(pa)pre-next=pa;∥当B,C无公共元素(即一个表已空),将A中剩余链入。 }∥算法 Union结東 [算法讨论]本算法先找结果链表的第一个元素,这是因为题目要求结果表要递増有序 (即删除重复元素)。这就要求当前待合并到结果表的元素要与其前驱比较。由于初始pre=A (头结点的头指针),这时的data域无意义,不能与后继比较元素大小,因此就需要确定第 一个元素。当然,不要这样作,而直接进入下面循环也可以,但在链入结点时,必须先判断 pre是否等于A,这占用了过多的时间。因此先将第一结点链入是可取的。 算法中的第二个问题是要求时间复杂度为0(A|+|B|+C)。这就要求各个表的工作指 针只能后移(即不能每次都从头指针开始査找)。本算法满足这一要求 最后一个问题是,当B,C有一表为空(即B和C已无公共元素时),要将A的剩余部分 链入结果表。 3.[题目分析]循环单链表L1和L2数据结点个数分别为m和n,将二者合成一个循环 单链表时,需要将一个循环链表的结点(从第一元素结点到最后一个结点)插入到另一循环
∥A,B 和 C 均是带头结点的递增有序的单链表,本算法实现 A= A∪(B∩C),使求解结 构保持递增有序。 {pa=A->next;pb=B->next;pc=C->next;∥设置三个工作指针。 pre=A; ∥pre 指向结果链表中当前待合并结点的前驱。 if(pa->datadata||pa->datadata)∥A 中第一个元素为结果表的第一元 素。 {pre->next=pa;pre=pa;pa=pa->next;} else{while(pb&&pc) ∥找 B 表和 C 表中第一个公共元素。 if(pb->datadata)pb=pb->next; else if(pb->data>pc->data)pc=pc->next; else break; ∥找到 B 表和 C 表的共同元素就退出 while 循环。 if(pb&&pc)∥ 因共同元素而非 B 表或 C 表空而退出上面 while 循环。 if(pa->data>pb->data)∥A 表当前元素值大于 B 表和 C 表的公共元素,先将 B 表元素链入。 {pre->next=pb;pre=pb;pb=pb->next;pc=pc->next;}∥ B,C 公共元素为结果 表第一元素。 }∥结束了结果表中第一元素的确定 while(pa&&pb&&pc) {while(pb&&pc) if(pb->datadata) pb=pb->next; else if(pb->data>pc->data) pc=pc->next; else break; ∥B 表和 C 表有公共元素。 if(pb&&pc) {while(pa&&pa->datadata) ∥先将 A 中小于 B,C 公共元素部分链入。 {pre->next=pa;pre=pa;pa=pa->next;} if(pre->data!=pb->data){pre->next=pb;pre=pb;pb=pb->next;pc=pc->next;} else{pb=pb->next;pc=pc->next;}∥ 若 A 中已有 B,C 公共元素,则不再存 入结果表。 } }∥ while(pa&&pb&&pc) if(pa) pre->next=pa; ∥当 B,C 无公共元素(即一个表已空),将 A 中剩余链入。 }∥算法 Union 结束 [算法讨论]本算法先找结果链表的第一个元素,这是因为题目要求结果表要递增有序 (即删除重复元素)。这就要求当前待合并到结果表的元素要与其前驱比较。由于初始 pre=A (头结点的头指针),这时的 data 域无意义,不能与后继比较元素大小,因此就需要确定第 一个元素。当然,不要这样作,而直接进入下面循环也可以,但在链入结点时,必须先判断 pre 是否等于 A,这占用了过多的时间。因此先将第一结点链入是可取的。 算法中的第二个问题是要求时间复杂度为 O(|A|+|B|+|C|)。这就要求各个表的工作指 针只能后移(即不能每次都从头指针开始查找)。本算法满足这一要求。 最后一个问题是,当 B,C 有一表为空(即 B 和 C 已无公共元素时),要将 A 的剩余部分 链入结果表。 3.[题目分析]循环单链表 L1 和 L2 数据结点个数分别为 m 和 n ,将二者合成一个循环 单链表时,需要将一个循环链表的结点(从第一元素结点到最后一个结点)插入到另一循环
链表的第一元素结点前即可。题目要求“用最快速度将两表合并“,因此应找结点个数少的 链表查其尾结点。 LinkedList Union (LinkedList Ll, L2:int m, n) ∥L1和L2分别是两循环单链表的头结点的指针,m和n分别是L1和L2的长度 ∥本算法用最快速度将L1和L2合并成一个循环单链表。 if(mnext!=1)p=p->next;∥查最后一个元素结点 p->next=L2->next;∥将L1循环单链表的元素结点插入到L2的第一元素结点 free(L1);∥释放无用头结点。 }∥处理完mnext!=2)p=p->next;∥查最后元素结点。 p>next=L1->next;∥将L2的元素结点插入到L1循环单链表的第一元素结 LI->next=L2->next ree(L2);∥释放无用头结点 }∥算法结束。 类似本题叙述的其它题解答如下: (1)[题目分析]本题将线性表la和1b连接,要求时间复杂度为0(1),且占用辅助空 间尽量小。应该使用只设尾指针的单循环链表。 LinkedList Union (LinkedList la, 1b ∥1a和1b是两个无头结点的循环单链表的尾指针,本算法将lb接在la后,成为一 个单循环链表 (g=la->next ∥q指向1a的第一个元素结点。 la->next=1b->next;∥将lb的最后元素结点接到Ib的第一元素 Ib->next=q ∥将1b指向la的第一元素结点,实现了1b接在1a后 ∥返回结果单循环链表的尾指针1b }∥算法结束 [算法讨论]若循环单链表带有头结点,则相应算法片段如下: :lb->next ∥q指向1b的头结点 1b-next=a->next;∥lb的后继结点为la的头结点。 la->next=q-next;∥la的后继结点为lb的第一元素结点 ∥释放1b的头结点 return(1b);∥返回结果单循环链表的尾指针1b (2)[题目分析]本题要求将单向链表ha和单向循环链表hb合并成一个单向链表,要求
链表的第一元素结点前即可。题目要求“用最快速度将两表合并“,因此应找结点个数少的 链表查其尾结点。 LinkedList Union(LinkedList L1,L2;int m,n) ∥L1 和 L2 分别是两循环单链表的头结点的指针,m 和 n 分别是 L1 和 L2 的长度。 ∥本算法用最快速度将 L1 和 L2 合并成一个循环单链表。 {if(mnext!=L1) p=p->next;∥查最后一个元素结点。 p->next=L2->next;∥将 L1 循环单链表的元素结点插入到 L2 的第一元素结点 前。 L2->next=L1->next; free(L1);∥释放无用头结点。 } }∥处理完 mnext!=L2) p=p->next;∥查最后元素结点。 p->next=L1->next;∥将 L2 的元素结点插入到 L1 循环单链表的第一元素结 点前。 L1->next=L2->next; free(L2);∥释放无用头结点。 } }∥算法结束。 类似本题叙述的其它题解答如下: (1)[题目分析]本题将线性表 la 和 lb 连接,要求时间复杂度为 O(1),且占用辅助空 间尽量小。应该使用只设尾指针的单循环链表。 LinkedList Union(LinkedList la,lb) ∥la 和 lb 是两个无头结点的循环单链表的尾指针,本算法将 lb 接在 la 后,成为一 个单循环链表。 { q=la->next; ∥q 指向 la 的第一个元素结点。 la->next=lb->next; ∥将 lb 的最后元素结点接到 lb 的第一元素。 lb->next=q; ∥将 lb 指向 la 的第一元素结点,实现了 lb 接在 la 后。 return(lb); ∥返回结果单循环链表的尾指针 lb。 }∥算法结束。 [算法讨论]若循环单链表带有头结点,则相应算法片段如下: q=lb->next; ∥q 指向 lb 的头结点; lb->next=la->next; ∥lb 的后继结点为 la 的头结点。 la->next=q->next; ∥la 的后继结点为 lb 的第一元素结点。 free(q); ∥释放 lb 的头结点 return(lb); ∥返回结果单循环链表的尾指针 lb。 (2)[题目分析]本题要求将单向链表 ha 和单向循环链表 hb 合并成一个单向链表,要求