算法与数据结构c语言习题参考答案章
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
p1->link=p->link;
free(p); /*删除结点p */
return 1;
}
8
【答】
数据结构
采用2.1.3节中单链表定义。
思路
依次遍历表中的每一个结点并计数,到第i+1个结点时实行删除。由于链表是无头结点的,所以在删除第一个结点时要特别注意。
算法
intdeleteindex_link_nohead(LinkList* pllist,int i){
算法:
int insertPre_link(LinkListllist,PNodep,DataTypex){
/*在llist带头结点的单链表中,p所指结点前面插入值为x的新结点*/
PNode p1;
if(llist==NULL)return0;
p1=llist;
while(p1!=NULL&&p1->link!=p)p1=p1->link; /*寻找p所指结点的前驱结点*/
x=palist->element[i];
palist->element[i]=palist->element[palist->n1i];
palist->element[palist->n1i]=x;
}
}
代价分析
该算法中包含一个for循环,其循环次数为n/2。因此,算法的时间代价为O(n)。
4
【答】
如果需要保持原来的顺序应该怎样做?这里提供一种可行的思路:从前向后遍历表,如果元素不是x,则继续向后;如果元素是x,则寻找其后第一个不是x的元素,将这两个元素互换。具体算法请读者自己实现。
6.
【答】
数据结构
采用2.1.3节中单链表定义。
思想:
由于在单链表中,只有指向后继结点的指针,所以只有首先找到p所指结点的前驱结点,然后才能完成插入。而找p所指结点的前驱结点,只能从单链表的第一个结点开始,使用与locate_link类似的方式进行搜索。
5
【答】
数据结构
采用2.1.2节中顺序表的定义。
思路
为了减少移动次数,可以采用快速检索的思想,用两个变量i,j记录顺序表中被处理的两端元素的下标,开始时i= 0,j=n1,边检索第i个元素边增加i,直到找到一个元素值等于x,再边检索第j个元素边减少j,直到找到一个元素值不等于x,把下标为j的元素移到下标为i的位置后重复上述过程,直到i≥j。另用一变量count记录删除了多少个元素。
return 1;
}
2
【答】
数据结构
采用2.1.2节中顺序表定义。
int deleteV_seq(PseqList palist, p, DataType x ){
/*在palist所指顺序表中删除值为x的元素*/
int p,q;
for(p=0;p<n;p++) /*查找值为x的元素的下标*/
if(x==palist->element[p]){
1.
1
A.2nB.n!C.n5D.10 000E.n*log2(n)
【答】10000<n*log2(n)<n5<2n<n!
2
A.n*log2(n)B.n+n2+n3C.24D.n0.5
【答】24<n0.5<n*log2(n)<n+n2+n3
3
A.5n5/2+n2/5B.6*log2(n) + 9n
C.3n4+n* log2(n)D.5n2+n3/2
【答】A:O (n5/2)B:O (n)C:O (n4)D:O (n2)
4
【答】按照增长率从低到高依次为:2000,log3n,log2n,n2/3,20n,4n2,3n。
n!的增长率比它们中的每一个都要大,应排在最后一位。
5.
int i=1;
while(i<=n)
{
printf(“i=%d\n”,i);
for(q=palist->n - 1; q>=p+1; q--)/*插入位置及之后的元素均后移一个位置*/
palist->element[q+1] = palist->element[q];
palist->element[p+1] = x;/*插入元素x */
palist->n = palist->n + 1;/*元素个数加1 */
for(q=p;q<palist->n-1;q++) /*被删除元素之后的元素均前移一个位置*/
palist->element[q] = palist->element[q+1];
palist->n = palist->n - 1;/*元素个数减1 */
return 1 ;
}
return 0;
}
3
【答】
return 1;
}
7.
【答】
数据结构
采用2.1.3节中单链表定义。
思想:
由于在单链表中,只有指向后继结点的指针,所以只有首先找到p所指结点的前驱结点,然后才能完成删除。而找p所指结点的前驱结点,只能从单链表的第一个结点开始,使用与locate_link类似的方式进行搜索。
int deleteP_link(LinkListllist,PNodep){
T(n) = 1 +n+n{1 +n+n[1 +n+ 2n+1]+1 +1}+ 1
= 3n3+ 3n2+4n+2
=O(n3)
2. 线性表
1.
【答】
数据结构
采用2.1.2节中顺序表定义。
int insertPost_seq(PseqList palist, int p, DataType x ){
/*在palist所指顺序表中下标为p的元素之后插入元素x */
/*在llist带头结点的单链表中,删除p所指的结点*/
PNode p1;
if(llist==NULL)return Null;
p1=llist;
while(p1!=NULL&&p1->link!=p)p1=p1->link; /*寻找p所指结点的前驱结点*/
if(p1=NULL)return 0;
i=i+1;
}
【答】循环控制变量i从1增加到n,循环体执行n次,第一句i的初始化执行次数为1,第二句执行n次,循环体中第一句printf执行n次,第二句i从1循环到n,共执行n次。所以该程序段总的时间代价为:
T(n) = 1 +n+ 2n= 3n+ 1 =O(n)
6.Hale Waihona Puke Baidu
int i=1;
while(i<=n)
int j;
PNode p, q;
if ((*pllist) == NULL || i < 0 || k <= 0) return FALSE;
if ( i = = 0) {/*如果需要删除从第一个结点开始的k个结点*/
for (j = 0; j < k && (*pllist) != NULL; j++) {
if(p1=NULL)return 0;
PNode q=(PNode)malloc(sizeof(struct Node));/*申请新结点*/
if(q=NULL) {printf(“Out of space!!!\n”);return 0;}
q->info=x;
q->link=p1->link;
p1->link=q;
顺序表的置逆算法
voidrev_seq(PSeqList palist){
DataTypex;
int count,i;
if(palist->n==0||palist->n==1)return;/*空表或只有一个元素,直接返回*/
count=palist->n/2;
for(i=0;i<count;i++){/*只需调换半个表的元素*/
free(q);
returnTRUE;
}
p=(*pllist);
j=0;
while(p->link!=NULL&&j<i1){/*寻找下标为i1的结点的地址*/
p=p->link;
j++;
}
if(p->link==NULL) returnFALSE;/*此元素不存在*/
q=p->link;
p->link=q->link;
free(q);
return TRUE;
}
代价分析
该算法访问单链表中前面i个结点,时间代价为O(i),最大不超过O(n)。
讨论
如果函数参数不是LinkList *类型而是LinkList类型,在删除i=0的结点时,程序不能正确实现,其原因请读者思考(考虑C语言的参数传递方式)。
如果单链表带表头结点,重写本题的算法。比较这两个算法,是否能体会到表头结点的作用。
数据结构
采用2.1.2节中顺序表定义。
思路
设置变量min,遍历整个表,不断更新当前已经经历过的元素的最小值即可。
为方便起见,事先假设表不为空。
算法
DataType min_seq(PSeqList palist){/*求非空顺序表中的最小数据元素*/
DataType min;
int i;
min=palist->element[0];/*初始化min*/
9
【答】
数据结构
采用2.1.3节单链表定义。
思路
这道题与上题相似,只需要增加计数即可。要注意的是应该判断给出的i和k是否合理,是不是会超出链表长度。
算法
int del_link_nohead(LinkList * pllist, int i, int k) {
/*删除单链表中从下标i开始的k个结点。删除成功返回TRUE,否则返回FALSE。*/
p->element[i] = p->element[j];
count++;
j;
}
}
i++;
}
p->n = p->ncount;
if (p->element[i] == x) p>n;
}
代价分析
该算法访问顺序表中每个元素各一次,时间代价为O(n)。
讨论
这个算法使用了一点技巧使得在中间删除元素时,避免了最后一串元素的移动。但是,它破坏了原来线性表中元素之间的顺序关系。
/*删除单链表中下标为i的结点。删除成功返回TRUE,否则返回FALSE。*/
int j;
PNode p,q;
if((*pllist)==NULL|| i < 0)returnFALSE;
if(i==0){/*如果需要删除第一个结点*/
q = (*pllist);
(*pllist)=(*pllist)->link;
while ((p->element[j] == x) && (i != j)) {
/*从后往前找不会被删除的元素,当i,j相等时退出循环,count记录从后往前找的过程中遇到了多少个要删的元素*/
j;
count++;
}
if (i == j) {
p->n = p->ncount1;
return;
}
else{
{
int j=1;
while(j<=n)
{
int k=1;
while(k<=n)
{
printf(“i=%d,j=%d,k=%d\n”,I,j,k);
k=k+1;
}
j=j+1;
}
i=i+1;
}
【答】循环控制变量i从1增加到n,最外层循环体执行n次,循环控制变量j从1增加到n,中间层循环体执行n次,循环控制变量k从1增加到n,最内层循环体执行n次,所以该程序段总的时间代价为:
算法
void delx_seq(PSeqList p, DataType x){
/*删除顺序表中所有值为x的元素,新顺序表可能不保持原有顺序*/
int i = 0, j = p->n1, count = 0;/*i定位于顺序表开始处,j定位于顺序表最后*/
while (i < j) {
if (p->element[i] == x) {/*找到了一个要删除的元素*/
for(i=1;i<palist->n;i++)/*min中保存的总是当前的最小数据*/
if (min>palist->element[i])
min=palist->element[i];
returnmin;
}
代价分析
该算法访问顺序表中每个元素各一次,时间代价为O(n)。
讨论
读者可以试图对上面的算法进行修改,使返回的值不是最小元素的值而是它的下标。
数据结构
采用2.1.2节中顺序表的定义。
思路
考虑对数组element[ ]进行置逆,即把第一个元素和最后一个元素换位置,把第二个元素和倒数第二个元素换位置……。
注意
这种调换的工作只需对数组的前一半元素进行,所以设置整数变量count用于存放数组长度的一半的值。大家可以考虑一下:为什么不能对整个数组进行如上的对元素“换位置”的工作?(提示:这样会将本来已经置逆的线性表又置逆回来,即又变成了原来的表。)
q = (*pllist);
(*pllist) = (*pllist)->link;
intq;
if (palist->n >=palist-> MAXNUM ){/*溢出*/
printf(“Overflow!\n”);
return 0;
}
if (p<0||p>palist->n-1){/*不存在下标为p的元素*/
printf(“Not exist! \n”); return 0;
}
free(p); /*删除结点p */
return 1;
}
8
【答】
数据结构
采用2.1.3节中单链表定义。
思路
依次遍历表中的每一个结点并计数,到第i+1个结点时实行删除。由于链表是无头结点的,所以在删除第一个结点时要特别注意。
算法
intdeleteindex_link_nohead(LinkList* pllist,int i){
算法:
int insertPre_link(LinkListllist,PNodep,DataTypex){
/*在llist带头结点的单链表中,p所指结点前面插入值为x的新结点*/
PNode p1;
if(llist==NULL)return0;
p1=llist;
while(p1!=NULL&&p1->link!=p)p1=p1->link; /*寻找p所指结点的前驱结点*/
x=palist->element[i];
palist->element[i]=palist->element[palist->n1i];
palist->element[palist->n1i]=x;
}
}
代价分析
该算法中包含一个for循环,其循环次数为n/2。因此,算法的时间代价为O(n)。
4
【答】
如果需要保持原来的顺序应该怎样做?这里提供一种可行的思路:从前向后遍历表,如果元素不是x,则继续向后;如果元素是x,则寻找其后第一个不是x的元素,将这两个元素互换。具体算法请读者自己实现。
6.
【答】
数据结构
采用2.1.3节中单链表定义。
思想:
由于在单链表中,只有指向后继结点的指针,所以只有首先找到p所指结点的前驱结点,然后才能完成插入。而找p所指结点的前驱结点,只能从单链表的第一个结点开始,使用与locate_link类似的方式进行搜索。
5
【答】
数据结构
采用2.1.2节中顺序表的定义。
思路
为了减少移动次数,可以采用快速检索的思想,用两个变量i,j记录顺序表中被处理的两端元素的下标,开始时i= 0,j=n1,边检索第i个元素边增加i,直到找到一个元素值等于x,再边检索第j个元素边减少j,直到找到一个元素值不等于x,把下标为j的元素移到下标为i的位置后重复上述过程,直到i≥j。另用一变量count记录删除了多少个元素。
return 1;
}
2
【答】
数据结构
采用2.1.2节中顺序表定义。
int deleteV_seq(PseqList palist, p, DataType x ){
/*在palist所指顺序表中删除值为x的元素*/
int p,q;
for(p=0;p<n;p++) /*查找值为x的元素的下标*/
if(x==palist->element[p]){
1.
1
A.2nB.n!C.n5D.10 000E.n*log2(n)
【答】10000<n*log2(n)<n5<2n<n!
2
A.n*log2(n)B.n+n2+n3C.24D.n0.5
【答】24<n0.5<n*log2(n)<n+n2+n3
3
A.5n5/2+n2/5B.6*log2(n) + 9n
C.3n4+n* log2(n)D.5n2+n3/2
【答】A:O (n5/2)B:O (n)C:O (n4)D:O (n2)
4
【答】按照增长率从低到高依次为:2000,log3n,log2n,n2/3,20n,4n2,3n。
n!的增长率比它们中的每一个都要大,应排在最后一位。
5.
int i=1;
while(i<=n)
{
printf(“i=%d\n”,i);
for(q=palist->n - 1; q>=p+1; q--)/*插入位置及之后的元素均后移一个位置*/
palist->element[q+1] = palist->element[q];
palist->element[p+1] = x;/*插入元素x */
palist->n = palist->n + 1;/*元素个数加1 */
for(q=p;q<palist->n-1;q++) /*被删除元素之后的元素均前移一个位置*/
palist->element[q] = palist->element[q+1];
palist->n = palist->n - 1;/*元素个数减1 */
return 1 ;
}
return 0;
}
3
【答】
return 1;
}
7.
【答】
数据结构
采用2.1.3节中单链表定义。
思想:
由于在单链表中,只有指向后继结点的指针,所以只有首先找到p所指结点的前驱结点,然后才能完成删除。而找p所指结点的前驱结点,只能从单链表的第一个结点开始,使用与locate_link类似的方式进行搜索。
int deleteP_link(LinkListllist,PNodep){
T(n) = 1 +n+n{1 +n+n[1 +n+ 2n+1]+1 +1}+ 1
= 3n3+ 3n2+4n+2
=O(n3)
2. 线性表
1.
【答】
数据结构
采用2.1.2节中顺序表定义。
int insertPost_seq(PseqList palist, int p, DataType x ){
/*在palist所指顺序表中下标为p的元素之后插入元素x */
/*在llist带头结点的单链表中,删除p所指的结点*/
PNode p1;
if(llist==NULL)return Null;
p1=llist;
while(p1!=NULL&&p1->link!=p)p1=p1->link; /*寻找p所指结点的前驱结点*/
if(p1=NULL)return 0;
i=i+1;
}
【答】循环控制变量i从1增加到n,循环体执行n次,第一句i的初始化执行次数为1,第二句执行n次,循环体中第一句printf执行n次,第二句i从1循环到n,共执行n次。所以该程序段总的时间代价为:
T(n) = 1 +n+ 2n= 3n+ 1 =O(n)
6.Hale Waihona Puke Baidu
int i=1;
while(i<=n)
int j;
PNode p, q;
if ((*pllist) == NULL || i < 0 || k <= 0) return FALSE;
if ( i = = 0) {/*如果需要删除从第一个结点开始的k个结点*/
for (j = 0; j < k && (*pllist) != NULL; j++) {
if(p1=NULL)return 0;
PNode q=(PNode)malloc(sizeof(struct Node));/*申请新结点*/
if(q=NULL) {printf(“Out of space!!!\n”);return 0;}
q->info=x;
q->link=p1->link;
p1->link=q;
顺序表的置逆算法
voidrev_seq(PSeqList palist){
DataTypex;
int count,i;
if(palist->n==0||palist->n==1)return;/*空表或只有一个元素,直接返回*/
count=palist->n/2;
for(i=0;i<count;i++){/*只需调换半个表的元素*/
free(q);
returnTRUE;
}
p=(*pllist);
j=0;
while(p->link!=NULL&&j<i1){/*寻找下标为i1的结点的地址*/
p=p->link;
j++;
}
if(p->link==NULL) returnFALSE;/*此元素不存在*/
q=p->link;
p->link=q->link;
free(q);
return TRUE;
}
代价分析
该算法访问单链表中前面i个结点,时间代价为O(i),最大不超过O(n)。
讨论
如果函数参数不是LinkList *类型而是LinkList类型,在删除i=0的结点时,程序不能正确实现,其原因请读者思考(考虑C语言的参数传递方式)。
如果单链表带表头结点,重写本题的算法。比较这两个算法,是否能体会到表头结点的作用。
数据结构
采用2.1.2节中顺序表定义。
思路
设置变量min,遍历整个表,不断更新当前已经经历过的元素的最小值即可。
为方便起见,事先假设表不为空。
算法
DataType min_seq(PSeqList palist){/*求非空顺序表中的最小数据元素*/
DataType min;
int i;
min=palist->element[0];/*初始化min*/
9
【答】
数据结构
采用2.1.3节单链表定义。
思路
这道题与上题相似,只需要增加计数即可。要注意的是应该判断给出的i和k是否合理,是不是会超出链表长度。
算法
int del_link_nohead(LinkList * pllist, int i, int k) {
/*删除单链表中从下标i开始的k个结点。删除成功返回TRUE,否则返回FALSE。*/
p->element[i] = p->element[j];
count++;
j;
}
}
i++;
}
p->n = p->ncount;
if (p->element[i] == x) p>n;
}
代价分析
该算法访问顺序表中每个元素各一次,时间代价为O(n)。
讨论
这个算法使用了一点技巧使得在中间删除元素时,避免了最后一串元素的移动。但是,它破坏了原来线性表中元素之间的顺序关系。
/*删除单链表中下标为i的结点。删除成功返回TRUE,否则返回FALSE。*/
int j;
PNode p,q;
if((*pllist)==NULL|| i < 0)returnFALSE;
if(i==0){/*如果需要删除第一个结点*/
q = (*pllist);
(*pllist)=(*pllist)->link;
while ((p->element[j] == x) && (i != j)) {
/*从后往前找不会被删除的元素,当i,j相等时退出循环,count记录从后往前找的过程中遇到了多少个要删的元素*/
j;
count++;
}
if (i == j) {
p->n = p->ncount1;
return;
}
else{
{
int j=1;
while(j<=n)
{
int k=1;
while(k<=n)
{
printf(“i=%d,j=%d,k=%d\n”,I,j,k);
k=k+1;
}
j=j+1;
}
i=i+1;
}
【答】循环控制变量i从1增加到n,最外层循环体执行n次,循环控制变量j从1增加到n,中间层循环体执行n次,循环控制变量k从1增加到n,最内层循环体执行n次,所以该程序段总的时间代价为:
算法
void delx_seq(PSeqList p, DataType x){
/*删除顺序表中所有值为x的元素,新顺序表可能不保持原有顺序*/
int i = 0, j = p->n1, count = 0;/*i定位于顺序表开始处,j定位于顺序表最后*/
while (i < j) {
if (p->element[i] == x) {/*找到了一个要删除的元素*/
for(i=1;i<palist->n;i++)/*min中保存的总是当前的最小数据*/
if (min>palist->element[i])
min=palist->element[i];
returnmin;
}
代价分析
该算法访问顺序表中每个元素各一次,时间代价为O(n)。
讨论
读者可以试图对上面的算法进行修改,使返回的值不是最小元素的值而是它的下标。
数据结构
采用2.1.2节中顺序表的定义。
思路
考虑对数组element[ ]进行置逆,即把第一个元素和最后一个元素换位置,把第二个元素和倒数第二个元素换位置……。
注意
这种调换的工作只需对数组的前一半元素进行,所以设置整数变量count用于存放数组长度的一半的值。大家可以考虑一下:为什么不能对整个数组进行如上的对元素“换位置”的工作?(提示:这样会将本来已经置逆的线性表又置逆回来,即又变成了原来的表。)
q = (*pllist);
(*pllist) = (*pllist)->link;
intq;
if (palist->n >=palist-> MAXNUM ){/*溢出*/
printf(“Overflow!\n”);
return 0;
}
if (p<0||p>palist->n-1){/*不存在下标为p的元素*/
printf(“Not exist! \n”); return 0;
}