数据结构算法与应用c语言描述答案.docx
《数据结构算法与应用c语言描述答案.docx》由会员分享,可在线阅读,更多相关《数据结构算法与应用c语言描述答案.docx(22页珍藏版)》请在冰豆网上搜索。
数据结构算法与应用c语言描述答案
数据结构算法与应用——c语言描述答案
【篇一:
《数据结构——用c语言描述》+课后题答案】
book/read/data-structure/h971111102.html
习题解答(唐策善版)(其他版本在上面)
第一章绪论(参考答案)
1.3
(1)o(n)
(2)
(2)o(n)
(3)(3)o(n)
(4)(4)o(n1/2)
(5)(5)执行程序段的过程中,x,y值变化如下:
循环次数xy
0(初始)91100
192100
293100
?
?
?
?
?
?
9100100
10101100
119199
1292100
?
?
?
?
?
?
2010199
219198
?
?
?
?
?
?
3010198
319197
到y=0时,要执行10*100次,可记为o(10*y)=o
(1)
1.52100,(2/3)n,logn2n,n1/2,n3/2,(3/2)n,nlogn2,2,n!
第二章线性表(参考答案)
在以下习题解答中,假定使用如下类型定义:
(1)顺序存储结构:
#definemaxsize1024
typedefintelemtype;//实际上,elemtype可以是任意类型
typedefstruct
{elemtypedata[maxsize];
intlast;//last表示终端结点在向量中的位置
}sequenlist;
(2)链式存储结构(单链表)
typedefstructnode
{elemtypedata;
structnode*next;
}linklist;
(3)链式存储结构(双链表)
typedefstructnode
{elemtypedata;
structnode*prior,*next;
nn
}dlinklist;
(4)静态链表
typedefstruct
{elemtypedata;
intnext;
}node;
nodesa[maxsize];
2.1头指针:
指向链表的指针。
因为对链表的所有操均需从头指针开始,即头指针具有标识链表的作用,所以链表的名字往往用头指针来标识。
如:
链表的头指针是la,往往简称为“链表la”。
头结点:
为了链表操作统一,在链表第一元素结点(称为首元结点,或首结点)之前增加的一个结点,该结点称为头结点,其数据域不无实际意义(当然,也可以存储链表长度,这只是副产品),其指针域指向头结点。
这样在插入和删除中头结点不变。
开始结点:
即上面所讲第一个元素的结点。
2.2只设尾指针的单循环链表,从尾指针出发能访问链表上的任何结点。
voidinsert(elemtypea[],intelenum,elemtypex)
//向量a目前有elenum个元素,且递增有序,本算法将x插入到向量a中,并保持向量的递增有序。
{inti=0,j;
while(ielenuma[i]=x)i++;//查找插入位置
for(j=elenum-1;j=i;j--)a[j+1]=a[j];//向后移动元素
a[i]=x;//插入元素
}//算法结束
voidrightrotate(elemtypea[],intn,k)
//以向量作存储结构,本算法将向量中的n个元素循环右移k位,且只用一个辅助空间。
{intnum=0;//计数,最终应等于n
intstart=0;//记录开始位置(下标)
while(numn)
{temp=a[start];//暂存起点元素值,temp与向量中元素类型相同
empty=start;//保存空位置下标
next=(start-k+n)%n;//计算下一右移元素的下标
while(next!
=start)
{a[empty]=a[next];//右移
num++;//右移元素数加1
empty=next;
next=(next-k+n)%n;//计算新右移元素的下标
}
a[empty]=temp;//把一轮右移中最后一个元素放到合适位置
num++;
start++;//起点增1,若numn则开始下一轮右移。
}
}//算法结束
算法二
算法思想:
先将左面n-k个元素逆置,接着将右面k个元素逆置,最后再将这n个元素逆置。
voidrightrotate(elemtypea[],intn,k)
//以向量作存储结构,本算法将向量中的n个元素循环右移k位,且只用一个辅助空间。
{elemtypetemp;
for(i=0;i(n-k)/2;i++)//左面n-k个元素逆置
{temp=a[i];a[i]=a[n-k-1-i];a[n-k-1-i]=temp;}
for(i=1;i=k;i++)//右面k个元素逆置
{temp=a[n-k-i];a[n-k-i]=a[n-i];a[n-i]=temp;}
for(i=0;in/2;i++)//全部n个元素逆置
{temp=a[i];a[i]=a[n-1-i];a[n-1-i]=temp;}
}//算法结束
voidinsert(linklist*l,elemtypex)
//带头结点的单链表l递增有序,本算法将x插入到链表中,并保持链表的递增有序。
{linklist*p=l-next,*pre=l,*s;
//p为工作指针,指向当前元素,pre为前驱指针,指向当前元素的前驱
s=(linklist*)malloc(sizeof(linklist));//申请空间,不判断溢出
s-data=x;
while(pp-data=x){pre=p;p=p-next;}//查找插入位置
pre-next=s;s-next=p;//插入元素
}//算法结束
voidinvert(linklist*l)
//本算法将带头结点的单链表l逆置。
//算法思想是先将头结点从表上摘下,然后从第一个元素结点开始,依次前插入以l为头结点的链表中。
{linklist*p=l-next,*s;
//p为工作指针,指向当前元素,s为p的后继指针
l-next=null;//头结点摘下,指针域置空。
算法中头指针l始终不变
while(p)
{s=p-next;//保留后继结点的指针
p-next=l-next;//逆置
l-next=p;
p=s;//将p指向下个待逆置结点
}
}//算法结束
(1)intlength1(linklist*l)
//本算法计算带头结点的单链表l的长度
{linklist*p=l-next;inti=0;
//p为工作指针,指向当前元素,i表示链表的长度
while(p)
{i++;p=p-next;}
return(i);
}//算法结束
(2)intlength1(nodesa[maxsize])
//本算法计算静态链表s中元素的个数。
{intp=sa[0].next,i=0;
//p为工作指针,指向当前元素,i表示元素的个数,静态链指针等于-1时链表结束while(p!
=-1)
{i++;p=sa[p].next;}
return(i);
}//算法结束
voidunion_invert(linklist*a,*b,*c)
//a和b是两个带头结点的递增有序的单链表,本算法将两表合并成
//一个带头结点的递减有序单链表c,利用原表空间。
{linklist*pa=a-next,*pb=b-next,*c=a,*r;
//pa,pb为工作指针,分别指向a表和b表的当前元素,r为当前逆置
//元素的后继指针,使逆置元素的表避免断开。
//算法思想是边合并边逆置,使递增有序的单链表合并为递减有序的单链表。
c-next=null;//头结点摘下,指针域置空。
算法中头指针c始终不变
while(papb)//两表均不空时作
if(pa-data=pb-data)//将a表中元素合并且逆置
{r=pa-next;//保留后继结点的指针
pa-next=c-next;//逆置
c-next=pa;
pa=r;//恢复待逆置结点的指针
}
else//将b表中元素合并且逆置
{r=pb-next;//保留后继结点的指针
pb-next=c-next;//逆置
c-next=pb;
pb=r;//恢复待逆置结点的指针
}
//以下while(pa)和while(pb)语句,只执行一个
while(pa)//将a表中剩余元素逆置
{r=pa-next;//保留后继结点的指针
pa-next=c-next;//逆置
c-next=pa;
pa=r;//恢复待逆置结点的指针
}
while(pb)//将b表中剩余元素逆置
{r=pb-next;//保留后继结点的指针
pb-next=c-next;//逆置
c-next=pb;
pb=r;//恢复待逆置结点的指针
}
free(b);//释放b表头结点
}//算法结束
voiddeleteprior(linklist*l)
//长度大于1的单循环链表,既无头结点,也无头指针,本算法删除*s的前驱结点{linklist*p=s-next,*pre=s;//p为工作指针,指向当前元素,
//pre为前驱指针,指向当前元素*p的前驱
while(p-next!
=s){pre=p;p=p-next;}//查找*s的前驱
pre-next=s;
free(p);//删除元素
}//算法结束
voidone_to_three(linklist*a,*b,*c)
//a是带头结点的的单链表,其数据元素是字符字母、字符、数字字符、其他字符。
本算法//将a表分成
//三个带头结点的循环单链表a、b和c,分别含有字母、数字和其它符号的同一类字符,利用原表空间。
{linklist*p=a-next,r;
//p为工作指针,指向a表的当前元素,r为当前元素的后继指针,使表避免断开。
//算法思想是取出当前元素,根据是字母、数字或其它符号,分别插入相应表中。
b=(linklist*)malloc(sizeof(linklist));//申请空间,不判断溢出
b-next=null;//准备循环链表的头结点
c=(linklist*)malloc(sizeof(linklist));//申请空间,不判断溢出
c-next=null;//准备循环链表的头结点
while(p)
{r=p-next;//用以记住后继结点
if(p-data=’a’p-data=’z’||p-data=’a’p-data=’z’)
{p-next=a-next;a-next=p;}//将字母字符插入a表
elseif(p-data=’0’p-data=’9’)
{p-next=b-next;b-next=p;}//将数字字符插入b表
else{p-next=c-next;c-next=p;}//将其它符号插入c表
p=r;//恢复后继结点的指针
}//while
}//算法结束
voidlocate(dlinklist*l)
//l是带头结点的按访问频度递减的双向链表,本算法先查找数据x,
//查找成功时结点的访问频度域增1,最后将该结点按频度递减插入链表中适当位置。
{linklist*p=l-next,*q;
//p为工作指针,指向l表的当前元素,q为p的前驱,用于查找插入位置。
while(pp-data!
=x)p=p-next;//查找值为x的结点。
if(!
p)return(“不存在值为x的结点”);
else{p-freq++;//令元素值为x的结点的freq域加1。
p-next-prir=p-prior;//将p结点从链表上摘下。
p-prior-next=p-next;
q=p-prior;//以下查找p结点的插入位置
while(q!
=lq-freqp-freq)q=q-prior;
p-next=q-next;q-next-prior=p;//将p结点插入
p-prior=q;q-next=p;
}
}//算法结束
第三章栈和队列(参考答案)
//从数据结构角度看,栈和队列是操作受限的线性结构,其顺序存储结构
//和链式存储结构的定义与线性表相同,请参考教材,这里不再重复。
3.11234213432144321
124321433241
132423143421
13422341
14322431
设入栈序列元素数为n,则可能的出栈序列数为c2nn=(1/n+1)*(2n!
/(n!
)2)
3.2证明:
由jk和pjpk说明pj在pk之前出栈,即在k未进栈之前pj已出栈,之后k进栈,
然后pk出栈;由jk和pjpk说明pj在pk之后出栈,即pj被pk压在下面,后进先出。
由
【篇二:
《数据结构——c语言描述》习题及答案耿国华】
题
一、问答题
1.什么是数据结构?
2.四类基本数据结构的名称与含义。
3.算法的定义与特性。
4.算法的时间复杂度。
5.数据类型的概念。
6.线性结构与非线性结构的差别。
7.面向对象程序设计语言的特点。
8.在面向对象程序设计中,类的作用是什么?
9.参数传递的主要方式及特点。
10.抽象数据类型的概念。
二、判断题
1.线性结构只能用顺序结构来存放,非线性结构只能用非顺序结构来存放。
2.算法就是程序。
3.在高级语言(如c、或pascal)中,指针类型是原子类型。
三、计算下列程序段中x=x+1的语句频度
for(i=1;i=n;i++)
for(j=1;j=i;j++)
for(k=1;k=j;k++)
x=x+1;
[提示]:
…
f(n)=[(1+2+3+……+n)+(12+22+32+……+n2)]/2
=[(1+n)n/2+n(n+1)(2n+1)/6]/2
=n(n+1)(n+2)/6
=n3/6+n2/2+n/3
区分语句频度和算法复杂度:
o(f(n))=o(n3)
四、试编写算法求一元多项式pn(x)=a0+a1x+a2x2+a3x3+…anxn的值pn(x0),并确定算法中的每一语句的执行次数和整个算法的时间复杂度,要求时间复杂度尽可能的小,规定算法中不能使用求幂函数。
注意:
本题中的输入ai(i=0,1,…,n),x和n,输出为pn(x0).通常算法的输入和输出可采用下列两种方式之一:
(1)通过参数表中的参数显式传递;
(2)通过全局变量隐式传递。
试讨论这两种方法的优缺点,并在本题算法中以你认为较好的一种方式实现输入和输出。
[提示]:
floatpolyvalue(floata[],floatx,intn){……}
核心语句:
p=1;(x的零次幂)
s=0;
i从0到n循环
s=s+a[i]*p;
p=p*x;
或:
p=x;(x的一次幂)
s=a[0];
i从1到n循环
s=s+a[i]*p;
p=p*x;
实习题
设计实现抽象数据类型“有理数”。
基本操作包括有理数的加法、减法、乘法、除法,以及求有理数的分子、分母。
第一章答案
1.3计算下列程序中x=x+1的语句频度
for(i=1;i=n;i++)
for(j=1;j=i;j++)
for(k=1;k=j;k++)
x=x+1;
【解答】x=x+1的语句频度为:
t(n)=1+(1+2)+(1+2+3)+……+(1+2+……+n)=n(n+1)(n+2)/6
1.4试编写算法,求pn(x)=a0+a1x+a2x2+…….+anxn的值pn(x0),并确定算法中每一语句的执行次数和整个算法的时间复杂度,要求时间复杂度尽可能小,规定算法中不能使用求幂函数。
注意:
本题中的输入为ai(i=0,1,…n)、x和n,输出为pn(x0)。
算法的输入和输出采用下列方法
(1)通过参数表中的参数显式传递
(2)通过全局变量隐式传递。
讨论两种方法的优缺点,并在算法中以你认为较好的一种实现输入输出。
【解答】
(1)通过参数表中的参数显式传递
优点:
当没有调用函数时,不占用内存,调用结束后形参被释放,实参维持,函数通
用性强,移置性强。
缺点:
形参须与实参对应,且返回值数量有限。
(2)通过全局变量隐式传递
优点:
减少实参与形参的个数,从而减少内存空间以及传递数据时的时间消耗
缺点:
函数通用性降低,移植性差
算法如下:
通过全局变量隐式传递参数
polyvalue()
{inti,n;
floatx,a[],p;
printf(“\nn=”);
scanf(“%f”,n);
printf(“\nx=”);
scanf(“%f”,x);
for(i=0;in;i++)
scanf(“%f”,a[i]);/*执行次数:
n次*/
p=a[0];
for(i=1;i=n;i++)
{p=p+a[i]*x;/*执行次数:
n次*/
x=x*x;}
printf(“%f”,p);
}
算法的时间复杂度:
t(n)=o(n)
通过参数表中的参数显式传递
floatpolyvalue(floata[],floatx,intn)
{
floatp,s;
inti;
p=x;
s=a[0];
for(i=1;i=n;i++)
{s=s+a[i]*p;/*执行次数:
n次*/
p=p*x;}
return(p);
}
算法的时间复杂度:
t(n)=o(n)
第2章线性表
习题
2.1
2.2描述以下三个概念的区别:
头指针,头结点,首元素结点。
填空:
(1)在顺序表中插入或删除一个元素,需要平均移动__一半__元素,具体移动的元
素个数与__插入或删除的位置__有关。
(2)在顺序表中,逻辑上相邻的元素,其物理位置______相邻。
在单链表中,逻
辑上相邻的元素,其物理位置______相邻。
(3)在带头结点的非空单链表中,头结点的存储位置由______指示,首元素结点
的存储位置由______指示,除首元素结点外,其它任一元素结点的存储位置由__其直接前趋的next域__指示。
2.3已知l是无表头结点的单链表,且p结点既不是首元素结点,也不是尾元素结点。
按要求从下列语句中选择合适的语句序列。
a.在p结点后插入s结点的语句序列是:
。
b.在p结点前插入s结点的语句序列是:
。
c.在表首插入s结点的语句序列是:
。
d.在表尾插入s结点的语句序列是:
。
供选择的语句有:
(1)p-next=s;
(2)p-next=p-next-next;
(3)p-next=s-next;
(4)s-next=p-next;
(5)s-next=l;
(6)s-next=null;
(7)q=p;
(8)while(p-next!
=q)p=p-next;
(9)while(p-next!
=null)p=p-next;
(10)p=q;
(11)p=l;
(12)l=
s;
(13)l=p;
2.4已知线性表l递增有序。
试写一算法,将x插入到l的适当位置上,以保持线性表l的有序性。
[提示]:
voidinsert(seqlist*l;elemtypex)
方法1
(1)找出应插入位置i,
(2)移位,(3)?
?
方法2参p.229
2.5写一算法,从顺序表中删除自第i个元素开始的k个元素。
[提示]:
注意检查i和k的合法性。
(集体搬迁,“新房”、“旧房”)
方法1以待移动元素下标m(“旧房号”)为中心,
计算应移入位置(“新房号”):
for(m=i-1+k;m=l-last;m++)
l-elem[m-k]=l-elem[m];
方法2同时以待移动元素下标m和应移入位置j为中心:
方法3以应移入位置j为中心,计算待移动元素下标:
【篇三:
唐策善数据结构答案-用c语言描述原版】
txt>2.1头指针:
指向链表的指针。
因为对链表的所有操均需从头指针开始,即头指针具有标识链表的作用,所以链表的名字往往用头指针来标识。
如:
链表的头指针是la,往往简称为“链表la”。
头结点:
为了链表操作统一,在链表第一元素结点(称为首元结点,或首结点)之前增加的一个结点,该结点称为头结点,其数据域不无实际意义(当然,也可以存储链表长度,这只是副产品),其指针域指向头结点。
这样在插入和删除中头结点不变。
开始结点:
即上面所讲第一个元素的结点。
2.2只设尾指针的单循环链表,从尾指针出发能访问链表上的任何结点。
voidinsert(elemtypea[],intelenum,elemtypex)
//向量a目前有elenum个元素,且递增有序,本算法将x插入到向量a中,并保持向量的递增有序。
{inti=0,j;
while(ielenuma[i]=x)i++;//查找插入位置for(j=elenum-1;j=i;j--)a[j+1]=a[j];//向后移动元素a[i]=x;//插入元素
}//算法结束
voidrightrotate(elemtypea[],intn,k)
//以向量作存储结构,本算法将向量中的n个元素循环右移k位,且只用一个辅助空间。
{intnum=0;//计数,最终应等于nintstart=0;//记录开始位置(下标)while(numn)
{temp=a[start];//暂存起点元素值,temp与向量中元素类型相同
empty=start;//保存空位置下标
next=(start