数据结构习题参考答案Word格式.docx
《数据结构习题参考答案Word格式.docx》由会员分享,可在线阅读,更多相关《数据结构习题参考答案Word格式.docx(67页珍藏版)》请在冰点文库上搜索。
![数据结构习题参考答案Word格式.docx](https://file1.bingdoc.com/fileroot1/2023-5/6/29e27a19-8f6a-4ec4-a126-c73e93249bf6/29e27a19-8f6a-4ec4-a126-c73e93249bf61.gif)
清华大学出版社
2008年12月
根据问题需求功能目标,此模型的所需的主要处理操作有插入、删除、查找和修改等基本操作。
所以,现用抽象数据类型bookList表示问题模型,其逻辑结构与基本操作的定义如下:
(1)逻辑结构
bookList=(D,{r})
D={bi|bi为bookType类型的元素,i=1,2,3,.....,n,n≥0}
r={<
bki,bi+1>
|i=1,2,…,n-1,n≥0}
(2)基本操作
①初始化
操作函数:
InitBookList(&
BL)。
初始条件:
图书表BL不存在。
操作结果:
构造一个空的图书表BL。
②求图书表长度
bookListLength(BL)。
图书表BL已存在。
返回图书表BL中所包含的数据元素(图书)的个数。
③取图书表中元素
getBook(BL,i,&
b)。
图书表BL已存在,且1≤i≤bookListLength(BL)。
用b返回图书表BL中的第i个数据元素的值。
④按编号查找
locateById(BL,id)。
图书表BL已存在,id是给定的一个图书编号。
返回图书表BL中图书编号为id的数据元素的位序,若这样的数据元素不存在,则返回0。
⑤按编号查找
locateByName(BL,i,name)。
图书表BL已存在,且1≤i≤bookListLength(BL),name是给定的一个图书名。
从图书表BL中第i个元素开始,查找图书名与给定name相等的第一个元素,若找到则返回其位序,否则返回0。
⑥插入图书
insertBook(&
BL,i,b)。
图书表BL已存在,且1≤i≤bookListLength(BL)+1。
在图书表BL的第i个位置上插入一个值为b的新元素,使线性表的长度增1。
⑦删除操作
deleteBook(&
BL,i,&
线性表L已存在,1≤i≤listLength(L)。
删除图书表BL的第i个数据元素,并用b返回其值,使线性表的长度减1。
11.
(1)
【解】函数体内为简单语句,时间复杂度为T(n)=O
(1)
【解】选取的基本语句为“if(a[i]>
a[k])k=i;
”其执行频度为n-1,时间复杂度为T(n)=O(n)。
【解】选取的基本语句为最内层的循环体语句“total+=a[i][j];
”,其执行频度为n(n+1)/2,时间复杂度为T(n)=O(n2)。
【解】选取的基本语句为最内层的循环体语句“c[i][j]+=a[i][k]*b[k][j];
”,其执行频度为n3,时间复杂度为T(n)=O(n3)。
(5)
【解】函数有两个并列的循环,其问题规模分别为n和m,对于第一个for循环选取的基本语句为“if(a[i]>
a[max])max=i;
”,其执行频度为n-1;
对于第二个for循环选取的基本语句为“if(b[i]<
b[min])min=i;
”,其执行频度为m-1。
所以该函数的时间复杂度为T(n,m)=O(n+m)。
(6)
【解】选取的基本语句为while的循环体,其执行频度为max{
},时间复杂度为T(n)=O(
)。
12.【解】算法
(1)中有两个并列的循环,每个循环的循环体语句执行次数均为n,故该函数的语句频度为2n。
算法
(2)只用了一个循环,其循环体语句执行次数为n,即该函数的语句频度为n。
所以算法
(1)与算法
(2)相比较,算法
(1)的时间效率更好。
但它们的时间复杂度都为O(n),这说明:
随着n值的增大,这两个函数执行时间的增长率相同,都是线性增长的。
13.【解】由题意,设计程序如下:
#include<
stdio.h>
stdlib.h>
structstuInfo{
intnum;
charname[18];
intscore;
};
voidinputInfo(structstuInfostus[],intn){
//输入n个同学信息存于数组stus中
inti;
for(i=0;
i<
n;
i++)
{printf("
输入%d个学生信息:
\n"
i+1);
printf("
学号:
"
);
scanf("
%d"
&
stus[i].num);
姓名:
%s"
stus[i].name);
成绩:
stus[i].score);
}
}
voidsortByScore(structstuInfostus[],intn){
//将数组stus中n个同学信息按成绩进行递减排序
inti,j,k;
structstuInfotemp;
n-1;
{k=i;
for(j=i+1;
j<
j++)
if(stus[j].score>
stus[k].score)k=j;
if(k!
=i){temp=stus[i];
stus[i]=stus[k];
stus[k]=temp;
voidoutputInfo(structstuInfostus[],intn){
//输出数组stus中n个同学信息报表
%6s%17s%6s\n"
"
学号"
姓名"
成绩"
);
%6d%17s%6d\n"
stus[i].num,stus[i].name,stus[i].score);
intmain(){
intn;
structstuInfo*stus;
输入学生数:
n);
stus=(structstuInfo*)malloc(n*sizeof(structstuInfo));
if(!
stus){printf("
内存空间溢出!
return-2;
inputInfo(stus,n);
sortByScore(stus,n);
outputInfo(stus,n);
system("
pause"
14.【解】由题意,函数设计如下:
StatusTriArea(doublea,doubleb,doublec,double&
area){
doubles;
if(a<
=0||b<
=0||c<
=0)returnERROR;
if(a+b<
=c||a+c<
=b||b+c<
=a)returnERROR;
s=(a+b+c)/2;
area=sqrt(s*(s-a)*(s-b)*(s-c));
returnOK;
15.【解】由题意,设欲交换的变量为int类型,则swap函数设计如下:
voidswap(int&
a,int&
b){
inttemp;
temp=a;
a=b;
b=t;
习题2参考答案
1.属于同一数据对象
2.A
3.2008
4.C
5.n-i+1、n-i
6.A
7.D
8.
(1)s->
next=p->
next;
p->
next=s;
(2)q=p->
next=q->
free(p);
(3)q->
next=L->
L->
next=q;
L->
next==NULL(4)q->
next=L;
L=q;
L==NULL
9.
(1)s->
next;
s->
pre=p;
p->
next->
pre=s;
(2)s->
pre=p->
pre;
s->
next=p;
pre->
(3)q=p->
p->
q->
free(q);
(4)q=p>
pre=q->
q->
(5)p->
next=p->
pre=p->
free(p);
(6)s->
pre=L;
pre=s;
10.略
11.【解】算法如下所示:
voidunion(ListLa,ListLb,List&
Lc)
{
inti=1,j=1,k=1,m;
LElemTypex,y,e;
while(!
listEmpty(La)&
&
!
listEmpty(Lb))
getElem(La,i,x);
getElem(Lb,j,y);
if(x<
y)
{listInsert(Lc,k,x);
i++;
else
{listInsert(Lc,k,y);
j++;
}
k++;
if(listEmpty(La))
for(m=j;
m<
=listLength(Lb);
m++)
listInsert(Lc,k++,getElem(Lb,m,e));
else
for(m=i;
=listLength(La);
listInsert(Lc,k++,getElem(La,m,e));
12.【解】要让插入新元素后的顺序表仍然按值递增有序,必须把x插入到表中第一个大于x的元素之前。
应先在表中找到该位置,然后将该位置以后的所有元素后移一位,空出一个位置,再将x插入。
算法如下所示:
StatusinsertOrderList(SqList&
L,LelemTypee){
if(L.length==L.listSize){//若存储空间已满,则追加存储空间
newBase=(LElemType*)realloc(L.base,
(L.listSize+ListSpaceIncr)*sizeof(LElemType));
if(!
newBase)returnOVERFLOW;
//存储空间扩充失败
L.base=newBase;
L.listSize+=ListSpaceIncr;
//存储空间扩充成功
for(i=L.length-1;
i>
=0;
i--)//查找插入位置,并进行元素后移
if(e<
L.base[i])L.base[i+1]=L.base[i];
elsebreak;
L.base[i+1]=e;
L.length++;
13.【解】算法如下所示。
voidreverse(SqList&
L)
{
LElemTypet;
=L.length/2-1;
t=L.base[i];
L.base[i]=L.base[L.length-i-1];
L.base[L.length-i-1]=t;
14.【解】算法如下所示:
voidInverseList(LinkList&
L){
LinkListp,q;
p=L->
next=NULL;
while(p){
q=p->
p=q;
15.【解】算法如下所示:
intcount(LinkListL,LElemTypex){
intn=0;
LNode*p;
while(p!
=NULL){
if(p->
data==x)n++;
p=p->
returnn;
16.【解】算法如下所示:
voiddelinsert(LinkList&
L){
LNode*p,*pre,*q;
p=L->
//p是链表的工作指针
pre=L;
//pre指向链表中数据域最小值结点的前驱
q=p;
//q指向数据域最小值结点,初始假定是首元结点
while(p->
next!
=NULL)
if(p->
data<
q->
data)//找到新的最小值结点
{pre=p;
p=p->
if(q!
=L->
next)//若最小值是第一元素结点,则不需再操作
pre->
//将最小值结点从链表上摘下
//将q结点插到头结点之后
17.【解】该算法的时间复杂度为O(n2),而算法2-16的时间复杂度为O(n),显然算法2-16的效率更高。
18.【解】不带头结点的单链表的插入操作listInsert(&
L,i,e)和删除操作listDelete(&
L,i,&
e)的算法如下:
StatuslistInsert(LinkList&
L,inti,LElemTypee){
//在不带头结点单链表L的第i个位置插入一个值为e的结点
LNode*p=L,*q;
//p用于查找第i-1个结点,初始指向头结点;
q用于指向欲插入结点
intj=1;
if(i==1)
q=(LNode*)malloc(sizeof(LNode));
//生成新结点
q)returnOVERFLOW;
q->
data=e;
while(j<
i-1&
p->
next){
}
if(j==i-1){//若p所指结点第j个结点为第i-1个结点时,在其后插入新结点
q=(LNode*)malloc(sizeof(LNode));
//将e赋给新结点的数据域
}
elsereturnERROR;
//第i-1个结点不存在,插入位置不正确
StatuslistDelete(LinkList&
L,inti,LElemType&
e){
//删除不带头结点单链表L的第i个元素
L=L->
while(j<
if(j==i-1&
next){//当p所指结点为第i-1个结点且第i个结点存在时,执行删除
e=q->
data;
//由e返回删除元素的值
若单链表带有头结点,则在首元结点的位置上插入新结点或者是删除首先结点的情况与在链表中间位置插入新结点或者是删除中间某个结点的情况是相同的,可以统一处理,但若单链表不带头结点,则在首元结点的位置上插入新结点或者是删除首先结点的情况需要特殊处理,由此可见头结点的好处。
19.【解】算法如下:
intlistLength(LinkListL){
//求循环单链表L的长度
LNode*p=L;
//p指向头结点
intj=0;
//j用于计数,表示p所指结点的位序
=L){//p所指结点存在
//指针后移,指向其后继
//计数器加1
returnj;
StatuslistEmpty(LinkListL){
//循环单链表的判空操作
if(L->
next==L)returnTRUE;
elsereturnFALSE;
20.【解】具体算法如下:
Statusswap(DLNode*p){
DLNode*q;
next==p->
prior)returnERROR;
prior=p;
prior=p->
prior;
prior->
prior=q;
21.【解】算法如下。
voidsetUnion(mySetType&
A,mySetTypeB){
//集合的并集运算,实现A=A∪B
inti,len1,len2,e;
len1=listLength(A);
len2=listLength(B);
for(i=1;
=len2;
i++){
getElem(B,i,e);
locateElem(A,e))listInsert(A,++len1,e);
voidsetIntersection(mySetTypeA,mySetTypeB,mySetType&
C){
//集合交集运算,实现C=A∩B
inti,e,len,k=0;
clearList(C);
k=0;
//集合C清空;
用k保存当前集合C的长度
len=listLength(A);
i<
=len;
i++){
getElem(A,i,e);
if(locateElem(B,e))listInsert(C,++k,e);
22.【解】利用单链表实现集合的创建操作的方法比较简单,这里不再给出,下面主要给出利用单链表实现集合的并集运算A=A∪B的算法。
其思想是用两个带头结点的单链表La和Lb表示两个集合A与B,遍历单链表Lb,针对Lb中的每个结点,看它在单链表La中是否存在,若不存在,则将其插入到单链表La中。
插入结点时,可采用头插法插入。
voidunion(LinkList&
La,LinkListLb){
LNode*pa,*pb,*s;
pb=Lb->
while(pb!
=NULL){
pa=La->
while(pa!
=NULL&
pa->
data!
=pb->
data)pa=pa->
if(pa==NULL){
s=(LinkList)malloc(sizeof(LNode));
data=pb->
next=La->
La->
pb=pb->
23.【解】一元多项式的创建操作、输出操作及测试主函数的参考算法如下:
voidCreatPoly(Poly&
L,intn){
//一元多项式的创建操作,其中n为一元多项式的项数
inti,coef,expn;
Polyp,s;
L=(Poly)malloc(sizeof(structPNode));
next=NULL;
p=L;
=n;
input%dthcoef:
i);
&
coef);
input%dthexpn:
expn);
s=(Poly)malloc(sizeof(structPNode));
coef=coef;
exp=expn;
p=s;
voidOutputPoly(PolyL){
//一元多项式的输出操作
intflag=1;
//flag用来是否为第一项的标识
Polyp;
while(p)
{if(flag){printf("
%dX^%d"
p->
coef,p->
exp);
flag=0;
elseprintf("
%+dX^%d"
intmain()
{PolyLa,Lb;
CreatPolyLa:
\tInputthenumberofitemsofLa:
CreatPoly(La,n);
\nLa(x)="
OutputPoly(La);
CreatPolyLb:
\tInputthenumberofitemsofLb:
CreatPoly(Lb,n);
\nLb(x)="
OutputPoly(Lb);
PolyAdd(La,Lb);
Lc(a)=La(x)+Lb(x)="
syste