.
(3)已知两个链表A和B分别表示两个集合,其元素递增排列。请设计算法求出A与B的交集,并存放于A链表中。
[题目分析]
只有同时出现在两集合中的元素才出现在结果表中,合并后的新表使用头指针Lc指向。pa和pb分别是链表La和Lb的工作指针,初始化为相应链表的第一个结点,从第一个结点开始进行比较,当两个链表La和Lb均为到达表尾结点时,如果两个表中相等的元素时,摘取La表中的元素,删除Lb表中的元素;如果其中一个表中的元素较小时,删除此表中较小的元素,此表的工作指针后移。当链表La和Lb有一个到达表尾结点,为空时,依次删除另一个非空表中的所有元素。
[算法描述]
void Mix(LinkList& La, LinkList& Lb, LinkList& Lc) { pa=La->next;pb=Lb->next;
pa和pb分别是链表La和Lb的工作指针,初始化为相应链表的第一个结点 Lc=pc=La; //用La的头结点作为Lc的头结点 while(pa&&pb)
{ if(pa->data==pb->data)∥交集并入结果表中。 { pc->next=pa;pc=pa;pa=pa->next; u=pb;pb=pb->next; delete u;}
else if(pa->data
while(pa) {u=pa; pa=pa->next; delete u;}∥ 释放结点空间 while(pb) {u=pb; pb=pb->next; delete u;}∥释放结点空间 pc->next=null;∥置链表尾标记。 delete Lb; //释放Lb的头结点 }
(4)已知两个链表A和B分别表示两个集合,其元素递增排列。请设计算法求出两个集合A和B 的差集(即仅由在A中出现而不在B中出现的元素所构成的集合),并以同样的形式存储,同时返回该集合的元素个数。
[题目分析]
求两个集合A和B的差集是指在A中删除A和B中共有的元素,即删除链表中的相应结点,所以要保存待删除结点的前驱,使用指针pre指向前驱结点。pa和pb分别是链表La和Lb的工作指针,初始化为相应链表的第一个结点,从第一个结点开始进行比较,当两个链表La和Lb均为到达表尾结点时,如果La表中的元素小于Lb表中的元素,pre置为La表的工作指针pa删除Lb表中的元素;如果其中一个表中的元素较小时,删除此表中较小的元素,此表的工作指针后移。当链表La和Lb有一个为空时,依次删除另一个非空表中的所有元素。
[算法描述]
9 / 76
. void Difference(LinkList& La, LinkList& Lb,int *n)
{∥差集的结果存储于单链表La中,*n是结果集合中元素个数,调用时为0 pa=La->next; pb=Lb->next;
∥pa和pb分别是链表La和Lb的工作指针,初始化为相应链表的第一个结点 pre=La; ∥pre为La中pa所指结点的前驱结点的指针 while(pa&&pb)
{if(pa->data
else if(pa->data>q->data)q=q->next; ∥B链表中当前结点指针后移 else {pre->next=pa->next; ∥处理A,B中元素值相同的结点,应删除 u=pa; pa=pa->next; delete u;} ∥删除结点
} }
(5)设计算法将一个带头结点的单链表A分解为两个具有相同结构的链表B、C,其中B表的结点为A表中值小于零的结点,而C表的结点为A表中值大于零的结点(链表A中的元素为非零整数,要求B、C表利用A表的结点)。
[题目分析]
B表的头结点使用原来A表的头结点,为C表新申请一个头结点。从A表的第一个结点开始,依次取其每个结点p,判断结点p的值是否小于0,利用前插法,将小于0的结点插入B表,大于等于0的结点插入C表。
[算法描述]
void DisCompose(LinkedList A) { B=A;
B->next= NULL; ∥B表初始化 C=new LNode;∥为C申请结点空间 C->next=NULL; ∥C初始化为空表 p=A->next; ∥p为工作指针 while(p!= NULL)
{ r=p->next; ∥暂存p的后继 if(p->data<0)
{p->next=B->next; B->next=p; }∥将小于0的结点链入B表,前插法 else {p->next=C->next; C->next=p; }∥将大于等于0的结点链入C表,前插法 p=r;∥p指向新的待处理结点。 }
}
(6)设计一个算法,通过一趟遍历在单链表中确定值最大的结点。 [题目分析]
10 / 76
. 假定第一个结点中数据具有最大值,依次与下一个元素比较,若其小于下一个元素,则设其下一个元素为最大值,反复进行比较,直到遍历完该链表。
[算法描述]
ElemType Max (LinkList L ){
if(L->next==NULL) return NULL;
pmax=L->next; //假定第一个结点中数据具有最大值 p=L->next->next;
while(p != NULL ){//如果下一个结点存在 }
return pmax->data;
if(p->data > pmax->data) pmax=p;//如果p的值大于pmax的值,则重新赋值 p=p->next;//遍历链表
(7)设计一个算法,通过遍历一趟,将链表中所有结点的链接方向逆转,仍利用原表的存储空间。
[题目分析]
从首元结点开始,逐个地把链表L的当前结点p插入新的链表头部。
[算法描述]
void inverse(LinkList &L) {// 逆置带头结点的单链表 L p=L->next; L->next=NULL; while ( p) {
q=p->next; // q指向*p的后继 p->next=L->next;
L->next=p; // *p插入在头结点之后 p = q; } }
(8)设计一个算法,删除递增有序链表中值大于mink且小于maxk的所有元素(mink和maxk是给定的两个参数,其值可以和表中的元素相同,也可以不同 )。
[题目分析]
分别查找第一个值>mink的结点和第一个值 ≥maxk的结点,再修改指针,删除值大于mink且小于maxk的所有元素。
[算法描述]
void delete(LinkList &L, int mink, int maxk) { p=L->next; //首元结点 while (p && p->data<=mink)
{ pre=p; p=p->next; } //查找第一个值>mink的结点 if (p)
11 / 76
. {while (p && p->data
// 查找第一个值 ≥maxk的结点 q=pre->next; pre->next=p; // 修改指针 while (q!=p)
{ s=q->next; delete q; q=s; } // 释放结点空间 }//if }
(9)已知p指向双向循环链表中的一个结点,其结点结构为data、prior、next三个域,写出算法change(p),交换p所指向的结点和它的前缀结点的顺序。
[题目分析]
知道双向循环链表中的一个结点,与前驱交换涉及到四个结点(p结点,前驱结点,前驱的前驱结点,后继结点)六条链。
[算法描述]
void Exchange(LinkedList p)
∥p是双向循环链表中的一个结点,本算法将p所指结点与其前驱结点交换。 {q=p->llink;
q->llink->rlink=p; ∥p的前驱的前驱之后继为p p->llink=q->llink; ∥p的前驱指向其前驱的前驱。 q->rlink=p->rlink; ∥p的前驱的后继为p的后继。 q->llink=p; ∥p与其前驱交换
p->rlink->llink=q; ∥p的后继的前驱指向原p的前驱 p->rlink=q; ∥p的后继指向其原来的前驱 }∥算法exchange结束。
(10)已知长度为n的线性表A采用顺序存储结构,请写一时间复杂度为O(n)、空间复杂度为O(1)的算法,该算法删除线性表中所有值为item的数据元素。
[题目分析]
在顺序存储的线性表上删除元素,通常要涉及到一系列元素的移动(删第i个元素,第i+1至第n个元素要依次前移)。本题要求删除线性表中所有值为item的数据元素,并未要求元素间的相对位置不变。因此可以考虑设头尾两个指针(i=1,j=n),从两端向中间移动,凡遇到值item的数据元素时,直接将右端元素左移至值为item的数据元素位置。
[算法描述]
void Delete(ElemType A[ ],int n)
∥A是有n个元素的一维数组,本算法删除A中所有值为item的元素。 {i=1;j=n;∥设置数组低、高端指针(下标)。 while(i {while(i 12 / 76 . 第3章 栈和队列 1.选择题 (1)若让元素1,2,3,4,5依次进栈,则出栈次序不可能出现在( )种情况。 A.5,4,3,2,1 B.2,1,5,4,3 C.4,3,1,2,5 D.2,3,5,4,1 答案:C 解释:栈是后进先出的线性表,不难发现C选项中元素1比元素2先出栈,违背了栈 的后进先出原则,所以不可能出现C选项所示的情况。 (2)若已知一个栈的入栈序列是1,2,3,…,n,其输出序列为p1,p2,p3,…,pn,若p1=n,则pi为( )。 A.i B.n-i C.n-i+1 D.不确定 答案:C 解释:栈是后进先出的线性表,一个栈的入栈序列是1,2,3,…,n,而输出序列的 第一个元素为n,说明1,2,3,…,n一次性全部进栈,再进行输出,所以p1=n,p2=n-1,…,pi=n-i+1。 (3)数组Q[n]用来表示一个循环队列,f为当前队列头元素的前一位置,r为队尾元素的位置,假定队列中元素的个数小于n,计算队列中元素个数的公式为( )。 A.r-f B.(n+f-r)%n C.n+r-f D.(n+r-f)%n 答案:D 解释:对于非循环队列,尾指针和头指针的差值便是队列的长度,而对于循环队列, 差值可能为负数,所以需要将差值加上MAXSIZE(本题为n),然后与MAXSIZE(本题为n)求余,即(n+r-f)%n。 (4)链式栈结点为:(data,link),top指向栈顶.若想摘除栈顶结点,并将删除结点的值保存到x中,则应执行操作( )。 A.x=top->data;top=top->link; B.top=top->link;x=top->link; C.x=top;top=top->link; 答案:A 解释:x=top->data将结点的值保存到x中,top=top->link栈顶指针指向栈顶下一结点, 即摘除栈顶结点。 (5)设有一个递归算法如下 int fact(int n) { //n大于等于0 if(n<=0) return 1; else return n*fact(n-1); } 则计算fact(n)需要调用该函数的次数为( )。 A. n+1 B. n-1 C. n D. n+2 答案:A 13 / 76 D.x=top->link;