《数据结构和算法》课后习题答案解析Word文档格式.docx
《《数据结构和算法》课后习题答案解析Word文档格式.docx》由会员分享,可在线阅读,更多相关《《数据结构和算法》课后习题答案解析Word文档格式.docx(54页珍藏版)》请在冰豆网上搜索。
![《数据结构和算法》课后习题答案解析Word文档格式.docx](https://file1.bdocx.com/fileroot1/2022-11/29/e58d6501-6c51-4531-8f48-13d316c04d2d/e58d6501-6c51-4531-8f48-13d316c04d2d1.gif)
last)/*将第i个元素以后与其值相同的元素删除*/
{k=i+1;
while(k<
=A->
last&
data[i]==A->
data[k])
k++;
/*使k指向第一个与A[i]不同的元素*/
n=k-i-1;
/*n表示要删除元素的个数*/
for(j=k;
j<
last;
j++)
A->
data[j-n]=A->
data[j];
/*删除多余元素*/
A->
last=A->
last-n;
i++;
}
3.写一个算法,从一个给定的顺序表A中删除值在x~y(x<
=y)之间的所有元素,要求以较高的效率来实现。
【提示】对顺序表A,从前向后依次判断当前元素A->
data[i]是否介于x和y之间,若是,并不立即删除,而是用n记录删除时应前移元素的位移量;
若不是,则将A->
data[i]向前移动n位。
n用来记录当前已删除元素的个数。
voiddelete(Seqlist*A,intx,inty)
n=0;
while(i<
last)
{if(A->
data[i]>
=x&
A->
data[i]<
=y)n++;
/*若A->
data[i]介于x和y之间,n自增*/
elseA->
data[i-n]=A->
data[i];
/*否则向前移动A->
data[i]*/
last-=n;
}
4.线性表中有n个元素,每个元素是一个字符,现存于向量R[n]中,试写一算法,使R中的字符按字母字符、数字字符和其它字符的顺序排列。
要求利用原来的存储空间,元素移动次数最小。
【提示】对线性表进行两次扫描,第一次将所有的字母放在前面,第二次将所有的数字放在字母之后,其它字符之前。
intfch(charc)/*判断c是否字母*/
{if(c>
='
a'
c<
z'
||c>
A'
Z'
)return
(1);
elsereturn(0);
intfnum(charc)/*判断c是否数字*/
0'
9'
)return
(1);
elsereturn(0);
voidprocess(charR[n])
{low=0;
high=n-1;
while(low<
high)/*将字母放在前面*/
{while(low<
high&
fch(R[low]))low++;
!
fch(R[high]))high--;
if(low<
high)
{k=R[low];
R[low]=R[high];
R[high]=k;
low=low+1;
high)/*将数字放在字母后面,其它字符前面*/
fnum(R[low]))low++;
while(low<
fnum(R[high]))high--;
if(low<
{k=R[low];
}
5.线性表用顺序存储,设计一个算法,用尽可能少的辅助存储空间将顺序表中前m个元素和后n个元素进行整体互换。
即将线性表:
(a1,a2,…,am,b1,b2,…,bn)改变为:
(b1,b2,…,bn,a1,a2,…,am)。
【提示】比较m和n的大小,若m<
n,则将表中元素依次前移m次;
否则,将表中元素依次后移n次。
voidprocess(Seqlist*L,intm,intn)
{if(m<
=n)
for(i=1;
i<
=m;
i++)
{x=L->
data[0];
for(k=1;
k<
=L->
k++)
L->
data[k-1]=L->
data[k];
data[L->
last]=x;
}
elsefor(i=1;
=n;
last];
for(k=L->
last-1;
k>
=0;
k--)
data[k+1]=L->
data[0]=x;
6.已知带头结点的单链表L中的结点是按整数值递增排列的,试写一算法,将值为x的结点插入到表L中,使得L仍然递增有序,并且分析算法的时间复杂度。
LinkListinsert(LinkListL,intx)
{p=L;
while(p->
next&
x>
p->
next->
data)
p=p->
next;
/*寻找插入位置*/
s=(LNode*)malloc(sizeof(LNode));
/*申请结点空间*/
s->
data=x;
/*填装结点*/
s->
next=p->
p->
next=s;
/*将结点插入到链表中*/
return(L);
}
7.假设有两个已排序(递增)的单链表A和B,编写算法将它们合并成一个链表C而不改变其排序性。
LinkListCombine(LinkListA,LinkListB)
{C=A;
rc=C;
pa=A->
/*pa指向表A的第一个结点*/
pb=B->
/*pb指向表B的第一个结点*/
free(B);
/*释放B的头结点*/
while(pa&
pb)/*将pa、pb所指向结点中,值较小的一个插入到链表C的表尾*/
if(pa->
data<
pb->
data)
{rc->
next=pa;
rc=pa;
pa=pa->
else
next=pb;
rc=pb;
pb=pb->
if(pa)rc->
elserc->
/*将链表A或B中剩余的部分链接到链表C的表尾*/
return(C);
8.假设长度大于1的循环单链表中,既无头结点也无头指针,p为指向该链表中某一结点的指针,编写算法删除该结点的前驱结点。
【提示】利用循环单链表的特点,通过s指针可循环找到其前驱结点p及p的前驱结点q,然后可删除结点*p。
vioddelepre(LNode*s)
{LNode*p,*q;
p=s;
while(p->
next!
=s)
{q=p;
p=p->
q->
free(p);
9.已知两个单链表A和B分别表示两个集合,其元素递增排列,编写算法求出A和B的交集C,要求C同样以元素递增的单链表形式存储。
【提示】交集指的是两个单链表的元素值相同的结点的集合,为了操作方便,先让单链表C带有一个头结点,最后将其删除掉。
算法中指针p用来指向A中的当前结点,指针q用来指向B中的当前结点,将其值进行比较,两者相等时,属于交集中的一个元素,两者不等时,将其较小者跳过,继续后面的比较。
LinkListIntersect(LinkListA,LinkListB)
{LNode*q,*p,*r,*s;
LinkListC;
C=(LNode*)malloc(sizeof(LNode));
C->
next=NULL;
r=C;
p=A;
q=B;
while(p&
q)
if(p->
data)p=p->
elseif(p->
data==q->
{s=(LNode*)malloc(sizeof(LNode));
data=p->
data;
r->
r=s;
q=q->
elseq=q->
r->
C=C->
returnC;
10.设有一个双向链表,每个结点中除有prior、data和next域外,还有一个访问频度freq域,在链表被起用之前,该域的值初始化为零。
每当在链表进行一次Locata(L,x)运算后,令值为x的结点中的freq域增1,并调整表中结点的次序,使其按访问频度的非递增序列排列,以便使频繁访问的结点总是靠近表头。
试写一个满足上述要求的Locata(L,x)算法。
【提示】在定位操作的同时,需要调整链表中结点的次序:
每次进行定位操作后,要查看所查找结点的freq域,将其同前面结点的freq域进行比较,同时进行结点次序的调整。
typedefstructdnode
{datatypedata;
intfreq;
structDLnode*prior,*next;
}DLnode,*DLinkList;
DlinkListLocate(DLinkListL,datatypex)
{p=L->
while(p&
data!
=x)p=p->
/*查找值为x的结点,使p指向它*/
if(!
p)return(NULL);
/*若查找失败,返回空指针*/
freq++;
/*修改p的freq域*/
while(p->
prior!
=L&
prior->
freq<
freq)/*调整结点的次序*/
{k=p->
data=k;
k=p->
freq;
freq=p->
freq=k;
prior;
return(p);
/*返回找到的结点的地址*/
3.3课后习题解答##
3.3.1选择题
1.向一个栈顶指针为Top的链栈中插入一个p所指结点时,其操作步骤为(C)。
A.Top->
next=p;
B.p->
next=Top->
Top->
C.p->
next=Top;
Top=p;
D.p->
Top=Top->
2.对于栈操作数据的原则是(B)。
A.先进先出B.后进先出C.后进后出D.不分顺序
3.若已知一个栈的入栈序列是1,2,3,…,n,其输出序列为p1,p2,p3,…,pN,若pN是n,则pi是(D)。
A.iB.n-iC.n-i+1D.不确定
4.表达式a*(b-c)+d的后缀表达式是(B)。
A.abcd*-+B.abc-*d+C.abc*-d+D.+-*abcd
5.采用顺序存储的两个栈共享空间S[1..m],top[i]代表第i个栈(i=1,2)的栈顶,栈1的底在S[1],栈2的底在S[m],则栈满的条件是(B)。
A.top[2]-top[1]|=0B.top[1]+1=top[2]
C.top[1]+top[2]=mD.top[1]=top[2]
6.一个栈的入栈序列是a,b,c,d,e,则栈的不可能的输出序列是(C)。
A.edcbaB.decbaC.dceabD.abcde
7.在一个链队列中,若f,r分别为队首、队尾指针,则插入s所指结点的操作为(B)。
A.f->
next=r;
f=s;
B.r->
r=s;
C.s->
D.s->
next=f;
8.用不带头结点的单链表存储队列时,在进行删除运算时(D)。
A.仅修改头指针B.仅修改尾指针
C.头、尾指针都要修改D.头、尾指针可能都要修改
9.递归过程或函数调用时,处理参数及返回地址,要用一种称为(C)的数据结构。
A.队列B.静态链表C.栈D.顺序表
10.栈和队都是(C)。
A.顺序存储的线性结构B.链式存储的非线性结构
C.限制存取点的线性结构D.限制存取点的非线性结构
3.3.2判断题
1.栈和队列的存储,既可以采用顺序存储结构,又可以采用链式存储结构。
2.任何一个递归过程都可以转换成非递归过程。
3.若输入序列为1,2,3,4,5,6,则通过一个栈可以输出序列3,2,5,6,4,1。
4.通常使用队列来处理函数的调用。
5.循环队列通常用指针来实现队列的头尾相接。
3.3.3简答题
1.循环队列的优点是什么?
如何判别它的空和满?
循环队列的优点是能够克服“假溢满”现象。
设有循环队列sq,队满的判别条件为:
(sq->
rear+1)%maxsize==sq->
front;
或sq->
num==maxsize。
队空的判别条件为:
sq->
rear==sq->
front。
2.栈和队列数据结构各有什么特点,什么情况下用到栈,什么情况下用到队列?
栈和队列都是操作受限的线性表,栈的运算规则是“后进先出”,队列的运算规则是“先进先出”。
栈的应用如数制转换、递归算法的实现等,队列的应用如树的层次遍历等。
3.什么是递归?
递归程序有什么优缺点?
一个函数在结束本函数之前,直接或间接调用函数自身,称为递归。
例如,函数f在执行中,又调用函数f自身,这称为直接递归;
若函数f在执行中,调用函数g,而g在执行中,又调用函数f,这称为间接递归。
在实际应用中,多为直接递归,也常简称为递归。
递归程序的优点是程序结构简单、清晰,易证明其正确性。
缺点是执行中占内存空间较多,运行效率低。
4.设有编号为1,2,3,4的四辆车,顺序进入一个栈式结构的站台,试写出这四辆车开出车站的所有可能的顺序(每辆车可能入站,可能不入站,时间也可能不等)。
1234,1243,1324,1342,1432,213,2143,2314,2341,2431,3214,3241,3421,4321
4.3课后习题解答###
4.3.1选择题
1.下面关于串的叙述错误的是(C)。
A.串是字符的有限序列
B.串既可以采用顺序存储,也可以采用链式存储
C.空串是由空格构成的串
D.模式匹配是串的一种重要运算
2.串的长度是指(B)。
A.串中所含不同字母的个数B.串中所含字符的个数
C.串中所含不同字符的个数D.串中所含非空格字符的个数
3.已知串S=‘aaab’,其Next数组值为(D)。
A.0123B.1123C.1231D.1211
4.二维数组M的成员是6个字符(每个字符占一个存储单元)组成的串,行下标i的范围从0到8,列下标j的范围从1到10,则存放M至少需要(D)个字节;
M的第8列和第5行共占(A)个字节;
若M按行优先方式存储,元素M[8][5]的起始地址与当M按列优先方式存储时的(C)元素的起始地址一致。
(1)A.90B.180C.240D.540
(2)A.108B.114C.54D.60
(3)A.M[8][5]B.M[3][10]C.M[5][8]D.M[0][9]
5.数组A中,每个元素的存储占3个单元,行下标i从1到8,列下标j从1到10,从首地址SA开始连续存放在存储器内,存放该数组至少需要的单元个数是(C),若该数组按行存放,元素A[8][5]的起始地址是(C),若该数组按列存放,元素A[8][5]的起始地址是(C)。
(1)A.80B.100C.240D.270
(2)A.SA+141B.SA+144C.SA+222D.SA+225
(3)A.SA+141B.SA+180C.SA+117D.SA+225
6.稀疏矩阵采用压缩存储,一般有(C)两种方法。
A.二维数组和三维数组B.三元组和散列
C.三元组表和十字链表D.散列和十字链表
4.3.2判断题
1.串相等是指两个串的长度相等。
2.KMP算法的特点是在模式匹配时指示主串的指针不会变小。
3.稀疏矩阵压缩存储后,必会失去随机存取功能。
4.数组是线性结构的一种推广,因此与线性表一样,可以对它进行插入,删除等操作。
5.若采用三元组存储稀疏矩阵,把每个元素的行下标和列下标互换,就完成了对该矩阵的转置运算。
6.若一个广义表的表头为空表,则此广义表亦为空表。
7.所谓取广义表的表尾就是返回广义表中最后一个元素。
4.3.3简答题
1.KMP算法较朴素的模式匹配算法有哪些改进?
KMP算法主要优点是主串指针不回溯。
当主串很大不能一次读入内存且经常发生部分匹配时,KMP算法的优点更为突出。
2.设字符串S=‘aabaabaabaac'
,P=‘aabaac'
。
(1)给出S和P的next值和nextval值;
(2)若S作主串,P作模式串,试给出利用KMP算法的匹配过程。
【解答】
(1)S的next与nextval值分别为012123456789和002002002009,p的next与nextval值分别为012123和002003。
(2)利用BF算法的匹配过程:
利用KMP算法的匹配过程:
第一趟匹配:
aabaabaabaac第一趟匹配:
aabaabaabaac
aabaac(i=6,j=6)aabaac(i=6,j=6)
第二趟匹配:
aabaabaabaac第二趟匹配:
aa(i=3,j=2)(aa)baac
第三趟匹配:
aabaabaabaac第三趟匹配:
a(i=3,j=1)(成功)(aa)baac
第四趟匹配:
aabaac(i=9,j=6)
第五趟匹配:
aa(i=6,j=2)
第六趟匹配:
a(i=6,j=1)
第七趟匹配:
(成功)aabaac(i=13,j=7)
3.假设按行优先存储整数数组A[9][3][5][8]时,第一个元素的字节地址是100,每个整数占4个字节。
问下列元素的存储地址是什么?
(1)a0000
(2)a1111(3)a3125(4)a8247
【解答】
(1)LOC(a0000)=100
(2)LOC(a1111)=100+(3*5*8*1+5*8*1+8*1+1)*4=776
(3)LOC(a3125)=100+(3*5*8*3+5*8*1+8*2+5)*4=1784
(4)LOC(a8247)=100+(3*5*8*8+5*8*2+8*4+7)*4=4816
4.假设一个准对角矩阵:
按以下方式存储于一维数组B[4m]中(m为一个整数):
1
2
3
4
5
6…k…4m-14m
a11
a12
a21
a22
a33
a34
a43
…
aij
a2m-1,2m
a2m,2m-1
a2m,2m
写出下标转换函数k=f(i,j)。
由题目可知,每一行有两个非0元素。
当i为奇数时,第i行的元素为:
ai,i、ai,(i+1),此时k=2*(i-1)+j-i=i+j-2
当i为偶数时,第i行的元素为:
ai,(i-1)、ai,i,此时k=2*(i-1)+j-I+1=i+j-1
综上所述,k=i+j-i%2-1。
5.设有n×
n的带宽为3的带状矩阵A,将其3条对角线上的元素存于数组B[3][n]中,使得元素B[u][v]=aij,试推导出从(i,j)到(u,v)的下标变换公式。
u=j-i+1
v=j-1
6.现有如下的稀疏矩阵A(如图所示),要求画出以下各种表示方法。
(1)三元组表表示法
(2)十字链表法。
(1)三元组表表示法:
ijv
6
7
1422
16-15
2213
233
34-6
5191
63