《第2章 线性表及其应用》习题解答.docx
- 文档编号:5219747
- 上传时间:2022-12-14
- 格式:DOCX
- 页数:13
- 大小:26.95KB
《第2章 线性表及其应用》习题解答.docx
《《第2章 线性表及其应用》习题解答.docx》由会员分享,可在线阅读,更多相关《《第2章 线性表及其应用》习题解答.docx(13页珍藏版)》请在冰豆网上搜索。
《第2章线性表及其应用》习题解答
《第2章线性表及其应用》习题解答
第2章线性表及其应用
第2章线性表及其应用
本章学习要点
◆掌握线性表的逻辑结构及相关概念。
◆掌握线性表的两种基本存储结构,即线性顺序表和线性链表的存储结构。
体会线性表在各种存储方式之间的差异及其各自的优缺点。
◆熟练掌握顺序表和链表上各种基本操作的实现过程。
◆灵活运用顺序表和链表的特点解决实际应用问题。
线性表是一种最基本、最常用的数据结构。
线性表有两种基本存储表示方法,即顺序存储表示和链表表示。
线性表的基本操作主要有插入、删除和查找等。
本章将具体给出线性表的定义、存储结构、基本操作及其算法实现,最后给出线性表的应用实例。
线性表的定义和基本运算
线性表的定义
线性表是n(n≥0)个同类型数据元素的有限序列:
a0,a1,a2,…,an-1。
记为:
Ln=(a0,a1,a2,…,an-1)。
其中:
a0是开始结点,an-1是终端结点,ak是ak+1的直接前驱结点,而ak+1是ak的直接后继结点(k=0,1,2,?
n-2);终端结点an-1没有后继结点,开始结点a0没有前驱结点;元素ai(i=0,1,2?
n-1)在表中的位置为i+1;元素的个数n称为线性表L的长度,长度为零的线性表叫空表。
需要说明的是:
在C/C++语言中,数组元素的下标是从0开始的,具有n个数据元素的数组A的所有元素为A[0],A[1],…,A[n-1]。
在线性表的定义中,第i个元素的下标为i-1,即元素的位置等于其下标加1。
日常生活中,线性表的例子很多:
【例】L10=是一个线性表。
其中的数据元素是整数,该线性表的长度为10。
按表中的排列顺序,元素1是第一个元素没有前驱,元素10是最后一
-.13.-
《数据结构与算法》
个元素没有后继。
【例】L36=是一个线性表。
其中的数据元素是所有数字字符和所有大写字母字符,线性表的长度为36。
按表中的排列顺序,元素?
0?
是第一个元素没有前驱,元素?
Z?
是最后一个元素没有后继。
【例】图所示的学生基本情况表L7也是一个线性表。
线性表中的元素是5个数据项组成的纪录,表的长度为7。
线性表的基本操作
线性表的基本运算主要有以下几种:
初始化InitList:
构造一个空线性表L的运算。
提取GetElem(L,i,&e):
提取表L中第i个元素的值到e的运算。
修改SetElem(&L,i,e):
修改表L中第i个元素的值为e的运算。
查找LocateElem(L,e):
查找表L中第一个值与e相同的元素的位置。
插入InsertList(&L,i,e):
将e插入到表L中的第i个位置。
删除DeleteList(&L,i,&e):
删除表L中的第i元素,并用e返回该元素的值。
求表长Length(L):
返回线性表L的长度。
遍历TraverseList(L):
依次输出L中每个元素的值。
在线性表的其它操作中,有些操作可以通过调用基本操作来实现,有些操作比如线性表的排序和归并等操作的实现将在以后的章节中进行。
线性表的顺序存储表示与实现
线性表的顺序存储
1.顺序表概念
一个线性表在计算机中可以用不同的方法来存储,其中最简单和最常用的一种存储方式是将线性表中的所有元素,按照其逻辑顺序依次存储到计算机内存中的从指定位置开始的一块连续的存储单元中。
用这种存储方式表示的线性表称为线性顺序表简称顺序表。
设顺序表Ln?
?
a0,a1,?
an?
1?
中元素a0的首地址为LOC(a0),每个元素需要占用的字节数为l,则表中任一元素ai的存储位置LOC(ai)可用下面的公式算出:
LOC(ai)?
LOC(a0)?
i?
l(i?
0,1,2,?
n?
1)顺序表中各元素在内存中所占的位置如
-.14.-
第2章线性表及其应用
图所示。
2.顺序表的结构定义
顺序表的存储结构和一维数组的存储结构极为相近;但是于在线性表中允许执行插入和删除等操作,也就是说一个线性表的长度是可变的,为适应这种情况在C++语言中用以下结构类型来表示顺序表。
typedefintElemType; //为了方便上机调试程序,本章假定数据元素的类型为整型constintMAXLEN=100;//定义顺序表存储空间大小的初始分配常量constintINCSIZE=50; //定义顺序表存储空间的扩充常量值structSqList //定义顺序表的结构类型为SqList{
ElemType*elem; //存储空间的基址 int length; //线性表的长度 int listsize; //当前表的存储容量 int incsize; //一次增补的容量值 };
在以上结构表示下,许多关于线性表的运算极易实现。
以下主要讨论关于顺序表的插入、删除、查找和遍历等操作。
顺序表中基本操作的实现
1.初始化操作InitList_Sq(&L)
该操作的功能是构造一个空线性顺序表L。
算法思想
在堆空间中为线性表动态分配一块连续的存储单元,返回首地址到elem;置线性表的长度值length为0;
置表的当前容量listsize为动态分配时的大小;置容量扩充值incsize的大小为INCSIZE。
线性表L的初始化存储结构如图所示。
-.15.-
《数据结构与算法》
算法实现
voidInitList_Sq(SqList&L,intmaxlength=MAXLEN,intincsize=INCSIZE){=newElemType[maxlength];
//动态分配一个长度为maxlength的连续存储空间,类型为ElemType,返回首地址到
}
=0;
=maxlength;=incsize;
2.提取操作GetElem_Sq(L,i,&e)
该操作将顺序表L中第i个元素的值赋值到e中,如果提取成功返回1否则返回0。
算法实现
intGetElem_Sq(SqListL,inti,ElemType&e){if(i)return0; //如果位置i不合理时返回0值else{e=[i-1]; //通过参数e得到第i个元素的值return1;}}
3.修改操作SetElem_Sq(&L,i,e)
修改操作将线性表L中第i个元素的值修改为e,如果修改成功返回1否则返回0。
算法实现
intSetElem_Sq(SqList&L,inti,ElemTypee){ if(i)return0; else {[i-1]=e;return1; }}
4.查找操作LocateElem_Sq(L,e)
查找操作的功能是查找顺序表L中第一个值与e相同的元素的位置,如果查找成功返回1
-.16.-
第2章线性表及其应用
查找失败返回0。
算法实现
intLocateElem_Sq(SqListL,ElemTypee){inti=0;while(i查找运算的基本操作为表中元素与数据e的比较。
假定表的长度为n,每个位置找到的机会都是相同的,即第i个位置找到的概率为pi?
1n,那么查找操作的平均比较次数为:
?
ni?
1pi?
i?
n?
12。
查找的时间复杂度是按最坏的情况来考虑,即查找的是最后一个元素或找
不到该元素,其比较次数为n次,所以查找的时间复杂度为:
T(n)?
?
(n)。
5.插入操作InsertList_Sq(&L,i,e)
插入操作的功能是将元素e插入到顺序表L中的第i个位置,同时修改L的长度。
如果插入成功返回1,不成功返回0。
算法思想
(1)先编写函数IncSize(&L),其功能是将顺序表L的最大存储量增加个元素的空间;
(2)如果插入的位置i不合理返回0,表示插入不成功;
(3)如果当前线性表的长度已经达到最大容量值,则调用函数IncSize(&L)扩充容量;
(4)将中第i个以后的所有元素都依次向后移动一个位置,为第i个元素的插入留出一个空位;
(5)置L中第i个元素的值为e;(6)将表的长度加1;
(7)返回值1表示插入成功。
算法实现
voidIncSize(SqList&L)
{//该函数的功能是另分配一个存储区并将L的最大存储量增加个记录的空间ElemType*a=newElemType[+];for(inti=0;i-.17.-
第2章线性表及其应用
表的头结点的指针。
并将其cur域的值置0值。
如果操作成功返回1,否则返回0。
算法设计代码如下:
intInitList_S(SLinkList&Space,int&p){if(p=NewSNode(Space)){Space[p].cur=0;return1;}return0;}静态链表p的插入操作InsertList_S(&Space,&p,i,e)
该操作从Space中摘取一个结点将data域的值置为e并将其插入到p中第i个位置。
如果操作成功返回1,否则返回0。
算法设计代码如下:
intInsertList_S(SLinkList&Space,int&p,inti,ElemTypee){inth=p,q,k=1;while(Space[h].cur&&k该操作删除p中第i个结点将data值赋值给e,并将资源归还给Space。
如果操作成功返回1,否则返回0。
算法设计代码如下:
intDeleteList_S(SLinkList&Space,int&p,inti,ElemType&e){inth=p,q,k=1;while(Space[h].cur&&k-.33.-
《数据结构与算法》
}
静态链表p的遍历操作TraverseList_S(Space,p)
该操作按序显示链表p中每一个结点的值。
算法设计代码如下:
voidTraverseList_S(SLinkListSpace,intp){inti=Space[p].cur;while(i){cout4.静态链表的综合演示程序
voidmain_S(){SLinkListSS;intp,i,num,n,k;ElemTypee;InitSpace_S(SS);if(!
InitList_S(SS,p)){cout>n;cout>e;if(!
InsertList_S(SS,p,i+1,e)){coutcout>num;switch(num){case1:
cout>i>>e;
-.34.-
第2章线性表及其应用
if(!
InsertList_S(SS,p,i,e))cout>i; if(!
DeleteList_S(SS,p,i,e))cout建立一个静态链表,输入长度:
12
输入12个结点的值:
100200300400500600700800900100011001200链表的初始内容为:
1002003004005006007008009001000110012001-在第i个结点前插入一个结点,2-删除第i个结点3-显示当前链表的内容,4-显示可用空间长度5-退出演示程序.输入选择:
1输入插入位置i和值e:
3333输入选择:
4输入选择:
1当前的可用空间长度为:
984输入插入位置i和值e:
5555输入选择:
2输入选择:
1输入删除位置i:
11输入插入位置i和值e:
7777第11个结点被删除,其值为:
900输入选择:
3输入选择:
4100200333300555400777500600700800900当前的可用空间长度为:
985100011001200输入选择:
3输入选择:
410020033330055540050060070080010001100当前的可用空间长度为:
9831200输入选择:
2输入选择:
5输入删除位置i:
7欢迎使用顺序表演示程序第7个结点被删除,其值为:
777
说明:
-.35.-
《数据结构与算法》
可用空间中应该去掉链表的头结点和空闲链表的头结点。
可多个静态链表共享同一个空闲链表。
于假定系统不能使用指针类型变量,即不能动态分配内存,因此当空间Space中的空闲链表为空时,将使静态链表的插入操作失败。
线性链表的应用举例
【例】有n个人围成一圈,顺序排号:
1、2、3、?
、n。
从第一个人开始报数,凡报到m的人退出圈子并记下此人的排号,当最后一个人退出圈子时,按出圈次序依次输出所有人原来的排号序列。
算法思想
建立一个长度为n的单链表L,其结点值依次为1、2、?
、n;
指针p每次向后移动m-1次使其指向出圈结点的直接前区结点;如果p的后继结点为NULL则p=L;
从链表L中删除p的后继结点q并输出q中的编号值;重复执行、、n次。
算法实现
voidmain(){intm,n,i,k;LinkListL=newNode,p,q; //定义头指针L指向头结点以及结点指针变量p、qcout>n>>m;p=L;for(i=1;inext=newNode;p=p->next;p->data=i;}p->next=NULL; //最后一个结点的指针域为NULLp=L;coutnext)p=L; p=p->next;}if(!
p->next)p=L;q=p->next; //以下语句实现:
删除结点q并输出其编号的值p->next=q->next;coutdata-.36.-
第2章线性表及其应用
deleteq;}cout程序运行演示结果为:
inputnm:
103↙所求编号序列为:
36927185104
算法分析
算法设计过程可知该算法的时间复杂度为O(n×m),空间复杂度为O
(1)。
【方法二】类似[例],通过直接调用单链表的基本操作来求解。
voidmain(){intm,n,i,k; //定义人数n、间隔数m、循环变量i和出圈人前驱结点的位置kElemTypee; //定义出圈人编号eLinkListL; //定义线性链表Lcout0;i--) //i为当前的链表长度{k=(k+m-1)%i; //计算出圈人结点在链表L中的前驱结点位置kDeleteList_L(L,k+1,e); //删除第k+1个结点并提取其编号到e中cout【例】逆置一个具有头结点的单向链表。
链表L逆置前的结构如图(a)所示,L逆置后的结构如图(b)所示。
算法思想
如果长度≤1程序结束;
指针p指向第一个结点,q指向第二个结点;置p的next域为NULL,r为q的直接后继;如果r为NULL转入否则执行;
置q的直接后继为p,置p的值为q,置q的值为r,置r为q的直接后继;
-.37.-
《数据结构与算法》
转入语句;
置q的直接后继为p,置L的直接后继为q。
算法实现
voidContray_L(LinkList&L){if(!
L->next||!
L->next->next)return;LinkListp=L->next,q=p->next,r;p->next=NULL;while(r=q->next){q->next=p;p=q;q=r;}q->next=p;L->next=q;}算法分析
设链表的长度为n,算法设计过程可知该算法的时间复杂度为O(n),空间复杂度为O
(1)。
【例】现有两个递增有序的带有头结点的单链表L1、L2,要求将L2中的结点归并到L1中并保持L1仍然有序,并且在归并过程中不另设结点。
算法思想
总的想法是,从前往后将L2中的结点逐个插入到L1中,如果在此过程中有一个结点插入到L1的末尾,则将L2中剩余的部分链接到L1的尾部即可。
算法实现
voidMerger_L(LinkList&L1,LinkList&L2){LinkListp=L1,q=L2->next,r;L2->next=NULL;while(p->next&&q){if(p->next->datadata) p=p->next;else{r=q;q=q->next; r->next=p->next; p->next=r; p=r; }}if(q)p->next=q;}算法分析
设L1的长度为m,L2的长度为n。
算法的时间复杂度为O(m+n),空间复杂度为O
(1)。
【例】用线性表表示一元多项式并实现多项式的加法、减法和乘法运算。
-.38.-
第2章线性表及其应用
1.多项式的线性表示法
在数学上,一个n次多项式Pn(x)可按升幂写成:
Pn(x)?
p0?
p1x?
p2x2pnxn,可见,Pn(x)其n+1个系数组成的系数向量P?
(p0,p1,p2,?
pn)唯一确定。
因此,在计算机中一个n次多项式可用一个长度为n+1的线性表P来表示,其中pi表示多项式中x的系数。
设多项式Qm(x)的系数向量为Q?
(q0,q1,q2,?
qm)且
miRn(x)?
Pn(x)?
Qm(x)的系数向量为:
R?
(p0?
q0,p1?
q1,p2?
q2,?
pm?
qm,pm?
1,?
pn)。
显然,对线性表P、Q、R,若均采用顺序存储结构,那么作多项式的加法运算十分简便。
但是,在实际应用中多项式的次数可能很高,且其中有大量的系数为零。
例如,多项式:
S(x)?
?
8?
?
,要用顺序存储时必须占用2501个元素的存储单元,这显然是不合理的。
为此,我们考虑只储存多项式的非零系数,此时必须连同它所表示的项的指数一起存放才行。
这样,用的序列就可以唯一地确定一个多项式了。
此时,S(x)可表示为:
S=((-8,0),(,50),(,2500))。
这显然也是一个线性表,表中元素是一个数对,并且关于元素中的第二个数据项是递增有序的。
既然S是线性表,同样存在其存储结构的选择问题。
于多项式相加的运算结果可能增加若干非零项,也可能减少若干个非零项,因此线性表会执行大量的插入和删除操作,在这种情况下不宜采用顺序存储结构,采用带有指针域的单链表表示一个多项式为宜。
上述多项式S(x)的单链表表示结构如图所示。
其中,头结点的指数域为-1,以示区别。
在C++语言中多项式的链表结构类型定义如下:
#include\
structPData //定义多项式中每一项的系数和指数结构类型:
PData{系数,指数}{doublecoef;intexpn;};
typedefstructPNode //定义多项式链表的结点结构类型:
PNode{data,next}{PDatadata;PNode*next;
-.39.-
《数据结构与算法》
}*Poly; //定义指向该结点PNode的指针类型Poly.2.初始化一个零多项式的操作voidInitPoly(Poly&p){p=newPNode;p->next=NULL;p->=-1;}
3.多项式加单项式的操作
算法思想
计算Poly+data的方法是:
从前往后将poly->项逐个取出并与项进行比较,将其插入到poly中的适当位置。
如果在poly中存在相同的指数域,则求相应的系数域的和,如果和为零,则删除掉poly中相应的结点。
算法实现
voidInsertAddPData(Poly&poly,PDatadata){Polyp=poly,q;while(p->next&&p->next->next;if(!
p->next||p->next->>) //插入一项到结点p的后面{q=newPNode;q->data=data;q->next=p->next;p->next=q;}else //与对应项的系数相加{p->next->+=;if(fabs(p->next->)next; p->next=q->next; deleteq;}}}
4.按序创建一个多项式
voidCreatePoly(Poly&poly){PDatadata;InitPoly(poly);cout-.40.-
第2章线性表及其应用
}
while
(1)
{cin>>>>;if(==0||5.按指数形式显示一个多项式
voidDispPoly(Polypoly){Polyp=poly;if(!
p->next)coutnext){p=p->next; if(p->>0)cout6.多项式加多项式操作voidAddPoly(Poly&p,Polyp1){Polypp=p1->next;while(pp){InsertAddPData(p,pp->data);pp=pp->next;}}
7.多项式减多项式操作voidSubPoly(Poly&p,Polyp1){Polypp=p1->next;PDatadata;while(pp){data=pp->data;*=-1;InsertAddPData(p,data);pp=pp->next;
-.41.-
《数据结构与算法》
}
}
8.多项式乘以多项式操作操作:
pvoidMulData(Poly&p,Polyp1,PDatad){PDatadd;Polyh=p1->next;while(h){dd=h->data;*=;+=;InsertAddPData(p,dd);h=h->next;}}
操作:
返回p×p1的值
PolyMulPoly(Polyp,Polyp1){Polypm,pp=p1->next;InitPoly(pm);while(pp){MulData(pm,p,pp->data);pp=pp->next;}returnpm;}
9.多项式操作的综合演示主程序voidmain(){Polyp,p1,p2,p3,p4;cout
/////p2/////p3-.42.-
第2章线性表及其应用
SubPoly(p3,p1);cout程序运行结果为:
createp:
输入多项式的系数和相应的指数(expn=-1结束):
2158-1100
P=+2X^1+5X^^11createp1:
输入多项式的系数和相应的指数(expn=-1结束):
70-5811900
P=+7X^0-5X^8+11X^9p2=p
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 第2章 线性表及其应用 第2章 线性表及其应用习题解答 线性 及其 应用 习题 解答