算法与数据结构C语言版课后习题答案机械工业出版社第1章绪论习题参考答案.docx
《算法与数据结构C语言版课后习题答案机械工业出版社第1章绪论习题参考答案.docx》由会员分享,可在线阅读,更多相关《算法与数据结构C语言版课后习题答案机械工业出版社第1章绪论习题参考答案.docx(13页珍藏版)》请在冰豆网上搜索。
算法与数据结构C语言版课后习题答案机械工业出版社第1章绪论习题参考答案
第3章概论习题参考答案
一、基础知识题
1. 简述下列概念
数据,数据元素,数据类型,数据结构,逻辑结构,存储结构,算法。
【解答】数据就是信息得载体,就是描述客观事物得数、字符,以及所有能输入到计算机中并被计算机程序识别与处理得符号得集合。
数据元素就是数据得基本单位。
在不同得条件下,数据元素又可称为元素、结点、顶点、记录等。
数据类型就是对数据得取值范围、数据元素之间得结构以及允许施加操作得一种总体描述。
每一种计算机程序设计语言都定义有自己得数据类型。
“数据结构”这一术语有两种含义,一就是作为一门课程得名称;二就是作为一个科学得概念。
作为科学概念,目前尚无公认定义,一般认为,讨论数据结构要包括三个方面,一就是数据得逻辑结构,二就是数据得存储结构,三就是对数据进行得操作(运算)。
而数据类型就是值得集合与操作得集合,可以瞧作就是已实现了得数据结构,后者就是前者得一种简化情况。
数据得逻辑结构反映数据元素之间得逻辑关系(即数据元素之间得关联方式或“邻接关系”),数据得存储结构就是数据结构在计算机中得表示,包括数据元素得表示及其关系得表示、数据得运算就是对数据定义得一组操作,运算就是定义在逻辑结构上得,与存储结构无关,而运算得实现则依赖于存储结构。
数据结构在计算机中得表示称为物理结构,又称存储结构。
就是逻辑结构在存储器中得映像,包括数据元素得表示与关系得表示。
逻辑结构与计算机无关。
算法就是对特定问题求解步骤得一种描述,就是指令得有限序列。
其中每一条指令表示一个或多个操作。
一个算法应该具有下列特性:
有穷性、确定性、可行性、输入与输出。
2。
数据得逻辑结构分哪几种,为什么说逻辑结构就是数据组织得主要方面?
【解答】数据得逻辑结构分为线性结构与非线性结构。
(也可以分为集合、线性结构、树形结构与图形即网状结构)、
逻辑结构就是数据组织得某种“本质性"得东西:
(1)逻辑结构与数据元素本身得形式、内容无关、
(2)逻辑结构与数据元素得相对位置无关。
(3)逻辑结构与所含数据元素得个数无关、
3. 试举一个数据结构得例子,叙述其逻辑结构、存储结构、运算三方面得内容。
【解答】如学生成绩表,逻辑结构就是线性结构,可以顺序存储(也可以链式存储),运算可以有插入、删除、查询、等等。
4. 简述算法得五个特性,对算法设计得要求。
【解答】算法得五个特性就是:
有穷性、确定性、可行性、零至多个输入与一至多个输出。
对算法设计得要求:
正确性,易读性,健壮性,与高得时空间效率(运算速度快,存储空间小)。
3.设n就是正整数,求下列程序段中带记号得语句得执行次数。
(1)i=1;k=0;
(2)i=1;j=0;
while(i<n) while(i+j<=n)
{k=k+50*i;i++; @ {if(i〉j)j++; @
} elsei++;} @
(3)x=y=0; (4)x=91;y=100;ﻩ
for(i=0;i〈n;i++) while(y〉0)
for(j=0;j100)
{x++; @ {x=x—10;y——;
for(k=0;k〈n;k++)@ }
y++; @ elsex++; @
}
【解答】
(1)n—1
(2)n为偶数时,均为ndiv2;
您为奇数时,分别为:
(ndiv2)+1与ndiv2
(3)n+1, n(n+1),n2,(n+1)n2,n3
(4)100,1000
4.有实现同一功能得两个算法A1与A2,其中A1得时间复杂度为Tl=O(2n),A2得时间复杂度为T2=O(n2),仅就时间复杂度而言,请具体分析这两个算法哪一个好?
【解答】对算法A1与A2得时间复杂度T1与T2取对数,得nlog2与2logn。
显然,当n<4时,算法A1好于A2;当n=4时,两个算法时间复杂度相同;当n〉4时,算法A2好于A1、
7、 选择题:
算法分析得目得就是()
A、找出数据结构得合理性 B、研究算法中得输入与输出得关系
C、分析算法得效率以求改进D、分析算法得易懂性与文档特点
【解答】C
二、算法设计题
8、 已知输入x,y,z三个不相等得整数,设计一个“高效”算法,使得这三个数按从小到大输出。
“高效"得含义就是用最少得元素比较次数、元素移动次数与输出次数。
voidBest()
{ //按序输出三个整数得优化算法
inta,b,c,t;
scanf(“%d%d%d",&a,&b,&c);
if(a>b)
{t=a;a=b;b=t:
} //a与b已正序
if(b〉c)
{t=c;c=b; //c已到位
if(a>t) {b=a;a=t;} //a与b已正序
elseb=t;
}//if
printf(“%d,%d,%d\n”,a,b,c);
//最佳2次比较,无移动;最差3次比较,7个赋值
}
6.在数组A[n]中查找值为k得元素,若找到则输出其位置i(1≤i≤n),否则输出0作为标志。
设计算法求解此问题,并分析在最坏情况下得时间复杂度
【题目分析】从后向前查找,若找到与k值相同得元素则返回其位置,否则返回0。
intSearch(ElemType A[n+1], ElemTypek)
{i=n;
wile(i〉=1)&&(A[i]!
=k))i-—;
if(i>=1)returni;
elsereturn 0;
}
当查找不成功时,总得比较次数为n+1次,所以最坏情况下时间复杂度为O(n)。
第2章线性表习题参考答案
一、基础知识题
2.1 试述头指针、头结点、元素结点、首元结点得区别,说明头指针与头结点得作
【解答】指向链表第一个结点(或为头结点或为首元结点)得指针称为头指针、“头指针”具有标识一个链表得作用,所以经常用头指针代表链表得名字,如链表L既就是指链表得名字就是L,也就是指链表得第一个结点得地址存储在指针变量L中,头指针为“NULL”则表示一个空表。
有时,我们在整个线性链表得第一个元素结点之前加入一个结点,称为头结点,它得数据域可以不存储任何信息(也可以做监视哨或存放线性表得长度等附加信息),指针域中存放得就是第一个数据结点得地址,空表时为空、 “头结点”得加入,使插入与删除等操作方便统一。
元素结点即就是数据结点,至少包括元素自身信息与其后继元素得地址两个域。
首元结点就是指链表中第一个数据元素得结点;为了操作方便,通常在链表得首元结点之前附设一个结点,称为头结点。
2.2分析顺序存储结构与链式存储结构得优缺点,说明何时应该利用何种结构、
【解答】①从空间上来瞧,当线性表得长度变化较大,难以估计其规模时,选用动态得链表作为存储结构比较合适,但链表除了需要设置数据域外,还要额外设置指针域,因此当线性表长度变化不大,易于事先确定规模时,为了节约存储空间,宜采用顺序存储结构、
②从时间上瞧,顺序表具有按元素序号随机访问得特点,在顺序表中按序号访问数据元素得时间复杂度为O
(1);而链表中按序号访问得时间复杂度为O(n)。
所以如果经常按序号访问数据元素,使用顺序表优于链表、
在顺序表中做插入删除操作时,平均移动大约表中一半得元素,因此n较大时顺序表得插入与删除效率低、在链表中作插入、删除,虽然也要找插入位置,但操作主要就是比较操作、从这个角度考虑显然链表优于顺序表、
总之,两种存储结构各有长短,选择那一种存储结构,由实际问题中得主要因素决定、
2。
3分析在顺序存储结构下插入与删除结点时平均需要移动多少个结点。
【解答】平均移动表中大约一半得结点,插入操作平均移动个结点,删除操作平均移动个结点、具体移动得次数取决于表长与插入、删除得结点得位置。
2。
4 为什么在单循环链表中常使用尾指针,若只设头指针,插入元素得时间复杂度如何?
【解答】单循环链表中无论设置尾指针还就是头指针都可以遍历表中任一个结点。
设置尾指针时,若在表尾进行插入元素或删除第一元素,操作可在O
(1)时间内完成;若只设置头指针,表尾进行插入或删除操作,需要遍历整个链表,时间复杂度为O(n)。
2、5在单链表、双链表、单循环链表中,若知道指针p指向某结点,能否删除该结点,时间复杂度如何?
【解答:
】以上三种链表中,若知道指针p指向某结点,都能删除该结点。
双链表删除p所指向得结点得时间复杂度为O
(1),而单链表与单循环链表上删除p所指向得结点得时间复杂度均为O(n)。
2、6 下面算法得功能就是什么?
LinkedListUnknown(LinkedListla)
{LNode*q,*p;
if(la&&la->next)
{q=la;la=la-〉next;p=la;
while(p->next)p=p-〉next;
p—〉next=q;q—>next=null;
}
returnla;
}
【解答】将首元结点删除并插入到表尾(设链表长度大于1)。
2.7选择题:
在循环双链表得*p结点之后插入*s结点得操作就是( )
la、p-〉next=s; s->prior=p;p->next—〉prior=s;s->next=p->next;
B、p-〉next=s; p-〉next-〉prior=s; s->prior=p; s—〉next=p->next;
lc、s->prior=p;s->next=p->next;p—>next:
=s; p-〉next->prior=s;
D、s->prior=p;s>next=p〉next; p>next->prior=s; p—〉next=s;
【解答】D
2.8选择题:
若某线性表最常用得操作就是存取任一指定序号得元素与在最后进行插入与删除运算,则利用()存储方式最节省时间。
la。
顺序表 B.双链表 lc.带头结点得双循环链表 D、单循环链表
【解答】la
二、算法设计题
2。
9 设ha与hb分别就是两个带头结点得非递减有序单链表得头指针,试设计算法,将这两个有序链表合并成一个非递增有序得单链表、要求使用原链表空间,表中无重复数据。
【题目分析】因为两链表已按元素值非递减次序排列,将其合并时,均从第一个结点起进行比较,将小得链入链表中,同时后移链表工作指针,若遇值相同得元素,则删除之、该问题要求结果链表按元素值非递增次序排列,故在合并得同时,将链表结点逆置。
LinkedList Union(LinkedListha,hb)
∥ha,hb分别就是带头结点得两个单链表得头指针,链表中得元素值按递增序排列
∥本算法将两链表合并成一个按元素值递减次序排列得单链表,并删除重复元素
{pa=ha—>next;∥pa就是链表ha得工作指针
pb=hb—>next; ∥pb就是链表hb得工作指针
ha->next=null;∥ha作结果链表得头指针,先将结果链表初始化为空
while(pa!
=null&& pb!
=null)∥当两链表均不为空时作
{while(pa-〉next &&pa—>data==pa->next->data)
{u=pa—>next;pa—〉next=u—>next;free(u)}∥删除pa链表中得重复元素
while(pb->next&& pb->data==pb-〉next->data)
{u=pb—>next;pb—>next=u-〉next;free(u)}∥删除pb链表中得重复元素
if(pa->data〈pb—>data)
{r=pa->next; ∥将pa得后继结点暂存于r
pa->next=ha->next; ∥将pa结点链于结果表中,同时逆置
ha-〉next=pa;
pa=r; ∥恢复pa为当前待比较结点
}
elseif(pb—>data〈pa-〉data)
{r=pb-〉next; ∥将pb 得后继结点暂存于r
pb-〉next=ha-〉next;∥将pb结点链于结果表中,同时逆置
ha—>next=pb;
pb=r; ∥恢复pb为当前待比较结点
}
else{u=pb;pb=pb->next;free(u)}∥删除链表pb与pa中得重复元素
}//while(pa!
=null&& pb!
=null)
if(pa) pb=pa; ∥避免再对pa写下面得while语句
while(pb!
=null) ∥将尚未到尾得表逆置到结果表中
{r=pb-〉next;pb->next=ha-〉next;ha—〉next=pb;pb=r;}
returnha
}∥算法Union结束
2、11 设p指向头指针为la得单链表中某结点,试编写算法,删除结点*p得直接前驱结点、
【题目分析】设*p就是单链表中某结点,删除结点*p得直接前驱结点,要找到*p得前驱结点得前驱*pre、进行如下操作:
u=pre—>next;pre—>next=u—〉next;free(u);ﻩ
LinkedList LinkedListDel(LinkedListla,LNode*p)
{∥删除单链表la上得结点*p得直接前驱结点,假定*p存在
pre=la;
if(pre-next==p)
printf(“*p就是链表第一结点,无前驱\n”) ;exit(0) ; }
ﻩwhile(pre—>next-〉next!
=p)
pre=pre->next;
u=pre—>next;pre->next=u-〉next;free(u);
return(la);
}
2、12设计一算法,将一个用循环链表表示得稀疏多项式分解成两个多项式,使这两个多项式各自仅有奇次幂或偶次幂项,并要求利用原链表中得结点空间来构造这两个链表。
【题目分析】设循环链表表示得多项式得结点结构为:
typedefstruct node
{int power; ∥幂
floatcoef; ∥系数
ElemType other; ∥其她信息
structnode*next;∥指向后继得指针
}PNode,*PolyLinkedList;
则可以从第一个结点开始,根据结点得幂就是奇数或偶数而将其插入到奇次幂或偶次幂项得链表中、假定用原链表保存偶次幂,要为奇次幂得链表生成一个表头,为了保持链表中结点得原来顺序,用一个指针指向奇次幂链表得表尾,注意链表分解时不能“断链”。
voidPolyDis(PolyLinkedListpoly)
∥将poly表示得多项式链表分解为各含奇次幂或偶次幂项得两个循环链表
{PolyLinkedListpoly2=(PolyLinkedList)malloc(sizeof(PNode));
∥poly2表示只含奇次幂得多项式
r2=poly2;∥r2就是只含奇次幂得多项式链表得尾指针
r1=poly; ∥r1就是只含偶次幂得多项式链表当前结点得前驱结点得指针
p=poly->next;∥链表带头结点,p指向第一个元素
while(p!
=poly)
if(p—>power%2)∥处理奇次幂
{r=p-〉next;∥暂存后继
r2—〉next=p;∥结点链入奇次幂链表
r2=p; ∥尾指针后移
p=r; ∥恢复当前待处理结点
}
else∥处理偶次幂
{r1—>next=p; r1=p;p=p->next;}
}
r->next=poly2;r1—〉next=poly;∥构成循环链表
}∥PolyDis
2、14 设单向链表得头指针为head,试设计算法,将链表按递增得顺序就地排序、
【题目分析】本题中得“就地排序”,可理解为不另辟空间,这里利用直接插入原则把链表整理成递增有序链表。
LinkedList LinkListInsertSort(LinkedListhead)
∥head就是带头结点得单链表,本算法利用直接插入原则将链表整理成递增得有序链表
{if(head—〉next!
=null) ∥链表不为空表
{p=head->next—〉next; ∥p指向第一结点得后继
head->next->next=null;
∥直接插入原则认为第一元素有序,然后从第二元素起依次插入
while(p!
=null)
{r=p->next; ∥暂存p得后继
q=head;
while(q->next&& q->next-〉data<p-〉data)
q=q->next;∥查找插入位置
p->next=q—>next; ∥将p结点链入链表
q->next=p;
p=r;
}
} }
2.15 已知递增有序得三个单链表分别代表集合A,B与C,设计算法实现A=A∪(B∩C),并使结果链表仍保持递增。
要求算法得时间复杂度为O(|A|+|B|+|C|)、其中,|A|为集合A得元素个数、
【题目分析】本题首先求B与C得交集,即求B与C中共有元素,再与A求并集,同时删除重复元素,以保持结果A递增。
LinkedListunion(LinkedListA,B,C)
∥A、B与C均就是带头结点得递增有序得单链表,本算法实现A=A∪(B∩C)
∥使结果表A保持递增有序
{pa=A->next;pb=B->next;pc=C->next;∥设置三个工作指针
pre=A;∥pre指向结果链表中当前待合并结点得前驱
A—>data=MaxElemType;∥同类型元素最大值,起监视哨作用
while(pa|| pb&&pc)
{while(pb&&pc)
if(pb->data
elseif(pb->data>pc-〉data)pc=pc-〉next;
else break;∥B表与C表有公共元素
if(pb &&pc)
{while(pa&&pa—〉data {pre->next=pa;pre=pa;pa=pa->next;}
if(pre—>data!
=pb->data)
{pre-〉next=pb;pre=pb;pb=pb-〉next;pc=pc—>next;}
else{pb=pb->next;pc=pc->next;}
∥若A中已有B,C公共元素,则不再存入结果表
}
}∥while(pa||pb&&pc)
if(pa) pre->next=pa;
elsepre->next=null; ∥当B,C无公共元素,将A中剩余链入
}∥算法Union结束
2。
16顺序表la与lb非递减有序,顺序表空间足够大。
试设计一种高效算法,将lb中元素合到la中,使新得la得元素仍保持非递减有序。
高效指最大限度地避免移动元素。
【题目分析】顺序存储结构得线性表得插入,其时间复杂度为O(n),平均移动近一半得元素。
线性表la与lb合并时,若从第一个元素开始,一定会造成元素后移,这不符合本题“高效算法”得要求、应从线性表得最后一个元素开始比较,大者放到最终位置上。
设两线性表得长度各为m与n,则结果表得最后一个元素应在m+n位置上、这样从后向前,直到第一个元素为止。
SeqListUnion(SeqListla,SeqListlb)
∥la与lb就是顺序存储得非递减有序线性表,本算法将lb合并到la中,元素仍非递减有序
{ m=la、last;n=lb、last;∥m,n分别为线性表la与lb得长度
k=m+n—1;∥k为结果线性表得工作指针(下标)
i=m-1;j=n—1; ∥i,j分别为线性表la与lb得工作指针(下标)
while(i>=0&& j〉=0)
if(la、data[i]>=lb。
data[j])la。
data[k—-]=la。
data[i——];
elsela、data[k—-]=lb、data[j--];
while(j>=0)la。
data[k--]=lb.data[j——];
la、last=m+n;
return la;
}
【算法讨论】算法中数据移动就是主要操作。
在最佳情况下(lb得最小元素大于la得最大元素),仅将lb得n个元素移(拷贝)到la中,时间复杂度为O(n),最差情况,la得所有元素都要移动,时间复杂度为O(m+n)、因数据合并到la中,所以在退出第一个while循环后,只需要一个while循环,处理lb中剩余元素。
第二个循环只有在lb有剩余元素时才执行,而在la有剩余元素时不执行。
本算法“最大限度得避免移动元素”,就是“一种高效算法”。
2、17已知非空线性链表由head指出,试写一算法,将链表中数据域值最小得那个结点移到链表得最前面。
要求:
不得额外申请新得链结点。
【题目分析】本题要求将链表中数据域值最小得结点移到链表得最前面。
首先要查找最小值结点、将其移到链表最前面,实质上就是将该结点从链表上摘下(不就是删除并回收空间),再插入到链表得最前面。
LinkedList Delinsert(LinkedList head)
∥本算法将非空线性链表head中数据域值最小得那个结点移到链表得最前面
{p=head->next;∥p就是链表得工作指针
pre=head; ∥pre指向链表中数据域最小值结点得前驱
q=p; ∥q指向数据域最小值结点,初始假定就是第一结点
while(p-〉next)
{if(p->next-〉datap=p->next;
}
if(q!
=head-〉next)∥若最小值就是第一元素结点,则不需再操作
{pre->next=q->next; ∥将最小值结点从链表上摘下
q-〉next=head->next; ∥将q结点插到链表最前面
head—>next=q;
}
}∥Delinsert
2.19 三个带头结点得线性链表la、lb与lc中得结点均依元素值自小至大非递减排列(可能存在两个以上值相同得结点),编写算法对la表进行如下操作:
使操作后得la中仅留下三个表中均包含得数据元素得结点,且没有值相