数据结构课后习题答案第二章 线性表.docx
- 文档编号:10426420
- 上传时间:2023-02-11
- 格式:DOCX
- 页数:27
- 大小:32.50KB
数据结构课后习题答案第二章 线性表.docx
《数据结构课后习题答案第二章 线性表.docx》由会员分享,可在线阅读,更多相关《数据结构课后习题答案第二章 线性表.docx(27页珍藏版)》请在冰豆网上搜索。
数据结构课后习题答案第二章线性表
第二章线性表
2.1描述以下三个概念的区别:
头指针,头结点,首元结点(第一个元素结点)。
并说明头指针和头结点的作用。
答:
头指针是一个指针变量,里面存放的是链表中首结点的地址,并以此来标识一个链表。
如链表H,链表L等,表示链表中第一个结点的地址存放在H、L中。
头结点是附加在第一个元素结点之前的一个结点,头指针指向头结点。
当该链表表示一个非空的线性表时,头结点的指针域指向第一个元素结点,为空表时,该指针域为空。
开始结点指第一个元素结点。
头指针的作用是用来惟一标识一个单链表。
头结点的作用有两个:
一是使得对空表和非空表的处理得以统一。
二是使得在链表的第一个位置上的操作和在其他位置上的操作一致,无需特殊处理。
2.2填空题
1、在顺序表中插入或删除一个元素,需要平均移动(表中一半)元素,具体移动的元素个数与(表长和该元素在表中的位置)有关。
2、顺序表中逻辑上相邻的元素的物理位置(必定)相邻。
单链表中逻辑上相邻的元素的物理位置(不一定)相邻。
3、在单链表中,除了首元结点外,任一结点的存储位置由(其直接前驱结点的链域的值)指示。
4、在单链表中设置头结点的作用是(插入和删除元素不必进行特殊处理)。
2.3何时选用顺序表、何时选用链表作为线性表的存储结构为宜?
答:
在实际应用中,应根据具体问题的要求和性质来选择顺序表或链表作为线性表的存储结构,通常有以下几方面的考虑:
1.基于空间的考虑。
当要求存储的线性表长度变化不大,易于事先确定其大小时,为了节约存储空间,宜采用顺序表;反之,当线性表长度变化大,难以估计其存储规模时,采用动态链表作为存储结构为好。
2.基于时间的考虑。
若线性表的操作主要是进行查找,很少做插入和删除操作时,采用顺序表做存储结构为宜;反之,若需要对线性表进行频繁地插入或删除等的操作时,宜采用链表做存储结构。
并且,若链表的插入和删除主要发生在表的首尾两端,则采用尾指针表示的单循环链表为宜。
2.10StatusDeleteK(SqList&a,inti,intk)//删除线性表a中第i个元素起的k个元素
{
if(i<1||k<0||i+k-1>a.length)returnINFEASIBLE;
for(count=1;i+count-1<=a.length-k;count++)//注意循环结束的条件
a.elem[i+count-1]=a.elem[i+count+k-1];
a.length-=k;
returnOK;
}//DeleteK
2.11设顺序表中的数据元素递增有序,试写一算法,将X插入到顺序表的适当位置上,以保持该表的有序性。
答:
因已知顺序表L是递增有序表,所以只要从顺序表终端结点(设为i位置元素)开始向前寻找到第一个小于或等于x的元素位置i后插入该位置即可。
在寻找过程中,由于大于x的元素都应放在x之后,所以可边寻找,边后移元素,当找到第一个小于或等于x的元素位置i时,该位置也空出来了。
算法如下:
//顺序表存储结构如题2.7
voidInsertIncreaseList(Seqlist*L,Datatypex)
{
inti;
if(L->length>=ListSize)
Error(“overflow");
for(i=L->length;i>0&&L->data[i-1]>x;i--)
L->data[i]=L->data[i-1];//比较并移动元素
L->data[i]=x;
L->length++;
}
2.12intListComp(SqListA,SqListB)//比较字符表A和B,并用返回值表示结果,值为正,表示A>B;值为负,表示A
{
for(i=1;A.elem[i]||B.elem[i];i++)
if(A.elem[i]!
=B.elem[i])returnA.elem[i]-B.elem[i];
return0;
}//ListComp
2.13试写一算法在带头结点的单链表上实现线性表操作LOCATE(L,X)。
Listnode*LocateNode(Linklisthead,DataTypekey)
{
ListNode*p=head->next;
While(p&&p->data!
=key)
p=p->next;
returnp;
}
2.14试写一算法在带头结点的单链表结构上实现线性表操作规程LENGTH(L)。
#include"stdio.h"
#defineMaxsize20
typedefintelemtype;
typedefstructnode{
elemtypedata;
structnode*next;
}lnode;
typedeflnode*linklist;
intlength_list(linklisthead)
{lnode*p=head;intj=0;
if(!
p){printf("error");exit(0);}
while(p->next)
{p=p->next;j++;}
returnj;
}
2.15已知L1和L2分别指向两个单链表的头结点,且已知其长度分别为m和n。
试写一算法将这两个链表连接在一起,请分析你的算法的时间复杂度。
解:
分析:
由于要进行的是两单链表的连接,所以应找到放在前面的那张表的表尾结点,再将后表的开始结点链接到前表的终端结点后即可。
该算法的主要时间消耗是用在寻找第一张表的终端尾结点上。
这两张单链表的连接顺序无要求,并且已知两表的表长,则为了提高算法效率,可选表长小的单链表在前的方式连接。
具体算法如下:
LinkListLink(LinkListL1,LinkListL2,intm,intn)
{//将两个单链表连接在一起
ListNode*p,*q,*s;
//s指向短表的头结点,q指向长表的开始结点,回收长表头结点空间
if(m<=n)
{s=L1;q=L2->next;free(L2);}
else{s=L2;q=L1->next;free(L1);}
p=s;
while(p->next)p=p->next;//查找短表终端结点
p->next=q;//将长表的开始结点链接在短表终端结点后
returns;
}
本算法的主要操作时间花费在查找短表的终端结点上,所以本算的法时间复杂度为:
O(min(m,n))
2.16见书后答案.
2.17StatusInsert(LinkList&L,inti,intb)//在无头结点链表L的第i个元素之前插入元素b
{
p=L;q=(LinkList*)malloc(sizeof(LNode));
q.data=b;
if(i==1)
{
q.next=p;L=q;//插入在链表头部
}
else
{
while(--i>1)p=p->next;
q->next=p->next;p->next=q;//插入在第i个元素的位置
}
}//Insert
2.18StatusDelete(LinkList&L,inti)//在无头结点链表L中删除第i个元素
{
if(i==1)L=L->next;//删除第一个元素
else
{
p=L;
while(--i>1)p=p->next;
p->next=p->next->next;//删除第i个元素
}
}//Delete
2.19StatusDelete_Between(Linklist&L,intmink,intmaxk)//删除元素递增排列的链表L中值大于mink且小于maxk的所有元素
{
p=L;
while(p->next->data<=mink)p=p->next;//p是最后一个不大于mink的元素
if(p->next) //如果还有比mink更大的元素
{
q=p->next;
while(q->data
p->next=q;
}
}//Delete_Between
2.20
StatusDelete_Equal(Linklist&L)//删除元素递增排列的链表L中所有值相同的元素
{
p=L->next;q=p->next;//p,q指向相邻两元素
while(p->next)
{
if(p->data!
=q->data)
{
p=p->next;q=p->next;//当相邻两元素不相等时,p,q都向后推一步
}
else
{
while(q->data==p->data)
{
free(q);
q=q->next;
}
p->next=q;p=q;q=p->next;//当相邻元素相等时删除多余元素
}//else
}//while
}//Delete_Equal
2.21试分别用顺序表作为存储结构,实现将线性表(a0,a1,...an-1)就地逆置的操作,所谓"就地"指辅助空间应为O
(1)。
答:
要将该表逆置,可以将表中的开始结点与终端结点互换,第二个结点与倒数第二个结点互换,如此反复,就可将整个表逆置了。
算法如下:
//顺序表结构定义同上题
voidReverseList(Seqlist*L)
{
DataTypetemp;//设置临时空间用于存放data
inti;
for(i=0;i<=L->length/2;i++)//L->length/2为整除运算
{temp=L->data[i];//交换数据
L->data[i]=L->data[L->length-1-i];
L->data[L->length-1-i]=temp;
}
}
2.22试写一算法,对单链表实现就地逆置。
答:
链表:
分析:
可以用交换数据的方式来达到逆置的目的。
但是由于是单链表,数据的存取不是随机的,因此算法效率太低。
可以利用指针改指来达到表逆置的目的。
具体情况入下:
(1)当链表为空表或只有一个结点时,该链表的逆置链表与原表相同。
(2)当链表含2个以上结点时,可将该链表处理成只含第一结点的带头结点链表和一个无头结点的包含该链表剩余结点的链表。
然后,将该无头结点链表中的所有结点顺着链表指针,由前往后将每个结点依次从无头结点链表中摘下,作为第一个结点插入到带头结点链表中。
这样就可以得到逆置的链表。
算法是这样的:
结点结构定义如下:
typedefcharDataType;//假设结点的数据域类型的字符
typedefstructnode{//结点类型定义
DataTypedata;//结点的数据域
structnode*next;//结点的指针域
}ListNode;
typedefListNode*LinkList;
ListNode*p;
LinkListhead;
LinkListReverseList(LinkListhead)
{//将head所指的单链表(带头结点)逆置
ListNode*p,*q;//设置两个临时指针变量
if(head->next&&head->next->next)
{ //当链表不是空表或单结点时
p=head->next;
q=p->next;
p->next=NULL;//将开始结点变成终端结点
while(q)
{//每次循环将后一个结点变成开始结点
p=q;
q=q->next;
p->next=head->next;
head->next=p;
}
returnhead;
}
returnhead;//如是空表或单结点表,直接返回head
}
2.23voidmerge1(LinkList&A,LinkList&B,LinkList&C)//把链表A和B合并为C,A和B的元素间隔排列,且使用原存储空间
{
p=A->next;q=B->next;C=A;
while(p&&q)
{
s=p->next;p->next=q;//将B的元素插入
if(s)
{
t=q->next;q->next=s;//如A非空,将A的元素插入
}
p=s;q=t;
}//while
}//merge1
2.24假设有两个按元素值递增有序排列的线性表A和B,均以单链表作为存储结构,请编写算法将A和B表归并成一个按元素值递减有序(即非递增有序,允许表中含有相同的元素)排列的线性有C,并要求利用原表(即A表和B表)的结点空间构造C表。
解:
voidreverse_merge(LinkList&A,LinkList&B,LinkList&C)//把元素递增排列的链表A和B合并为C,且C中元素递减排列,使用原空间
{
pa=A->next;pb=B->next;pre=NULL;//pa和pb分别指向A,B的当前元素
while(pa||pb)
{
if(pa->data
pb)
{
pc=pa;q=pa->next;pa->next=pre;pa=q;//将A的元素插入新表
}
else
{
pc=pb;q=pb->next;pb->next=pre;pb=q;//将B的元素插入新表
}
pre=pc;
}
C=A;A->next=pc;//构造新表头
}//reverse_merge
分析:
本算法的思想是,按从小到大的顺序依次把A和B的元素插入新表的头部pc处,最后处理A或B的剩余元素.
2.25voidSqList_Intersect(SqListA,SqListB,SqList&C)//求元素递增排列的线性表A和B的元素的交集并存入C中
{
i=1;j=1;k=0;
while(A.elem[i]&&B.elem[j])
{
if(A.elem[i] if(A.elem[i]>B.elem[j])j++; if(A.elem[i]==B.elem[j]) { C.elem[++k]=A.elem[i];//当发现了一个在A,B中都存在的元素, i++;j++;//就添加到C中 } }//while }//SqList_Intersect 2.26 voidLinkList_Intersect(LinkListA,LinkListB,LinkList&C)//在链表结构上重做上题 { p=A->next;q=B->next; pc=(LNode*)malloc(sizeof(LNode)); while(p&&q) { if(p->data elseif(p->data>q->data)q=q->next; else { s=(LNode*)malloc(sizeof(LNode)); s->data=p->data; pc->next=s;pc=s; p=p->next;q=q->next; } }//while C=pc; }//LinkList_Intersect 2.27 voidSqList_Intersect_True(SqList&A,SqListB)//求元素递增排列的线性表A和B的元素的交集并存回A中 { i=1;j=1;k=0; while(A.elem[i]&&B.elem[j]) { if(A.elem[i] elseif(A.elem[i]>B.elem[j])j++; elseif(A.elem[i]! =A.elem[k]) { A.elem[++k]=A.elem[i];//当发现了一个在A,B中都存在的元素 i++;j++;//且C中没有,就添加到C中 } }//while while(A.elem[k])A.elem[k++]=0; }//SqList_Intersect_True 2.28 voidLinkList_Intersect_True(LinkList&A,LinkListB)//在链表结构上重做上题 { p=A->next;q=B->next;pc=A; while(p&&q) { if(p->data elseif(p->data>q->data)q=q->next; elseif(p->data! =pc->data) { pc=pc->next; pc->data=p->data; p=p->next;q=q->next; } }//while }//LinkList_Intersect_True 2.29 voidSqList_Intersect_Delete(SqList&A,SqListB,SqListC) { i=0;j=0;k=0;m=0;//i指示A中元素原来的位置,m为移动后的位置 while(i { if(B.elem[j] elseif(B.elem[j]>C.elem[k])k++; else { same=B.elem[j];//找到了相同元素same while(B.elem[j]==same)j++; while(C.elem[k]==same)k++;//j,k后移到新的元素 while(i A.elem[m++]=A.elem[i++];//需保留的元素移动到新位置 while(i } }//while while(i A.elem[m++]=A.elem[i++];//A的剩余元素重新存储。 A.length=m; }//SqList_Intersect_Delete 分析: 先从B和C中找出共有元素,记为same,再在A中从当前位置开始,凡小于same的 元素均保留(存到新的位置),等于same的就跳过,到大于same时就再找下一个same. 2.30 voidLinkList_Intersect_Delete(LinkList&A,LinkListB,LinkListC)//在链表结构上重做上题 { p=B->next;q=C->next;r=A-next; while(p&&q&&r) { if(p->data elseif(p->data>q->data)q=q->next; else { u=p->data;//确定待删除元素u while(r->next->datanext;//确定最后一个小于u的元素指针r if(r->next->data==u) { s=r->next; while(s->data==u) { t=s;s=s->next;free(t);//确定第一个大于u的元素指针s }//while r->next=s;//删除r和s之间的元素 }//if while(p->data=u)p=p->next; while(q->data=u)q=q->next; }//else }//while }//LinkList_Intersect_Delete 2.31假设在长度大于1的单循环链表中,既无头结点也无头指针。 s为指向链表中某个结点的指针,试编写算法删除结点*s的直接前趋结点。 解: 已知指向这个结点的指针是*s,那么要删除这个结点的直接前趋结点,就只要找到一个结点,它的指针域是指向*s的直接前趋,然后用后删结点法,将结点*s的直接前趋结点删除即可。 算法如下: voidDeleteNode(ListNode*s) {//删除单循环链表中指定结点的直接前趋结点 ListNode*p,*q; p=s; while(p->next->next! =s) p=p->next; //删除结点 q=p->next; p->next=q->next; free(p);//释放空间 } 注意: 若单循环链表的长度等于1,则只要把表删空即可。 2.32已知有一个单向循环链表,其每个结点中含三个域: prior、data和next,其中data为数据域,next为指向后继结点的指针域,prior也为指针域,但它的值为空,试编写算法将此单向循环链表改为双向循环
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 数据结构课后习题答案第二章 线性表 数据结构 课后 习题 答案 第二 线性