数据结构-线性表习题及解析
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
线性表典型例题
一、单项选择题
[例7-1]在数据结构中,与所使用计算机无关的数据叫( ①)结构;链表是一种采用( ②)存储结构存储的线性表;链表适用于( ③)查找;在链表中进行( ④)操作的效率比在线性表中进行该操作的效率高。
①A.存储B.物理C.逻辑D.物理和逻辑
②A.顺序B.网状C.星式D.链式
③A.顺序B.二分法C.顺序及二分法D.随机
④A.二分法查找B.快速查找C.顺序查找D.插入
解析:本题考查的是基本概念。
本题答案为:①C;②D;③A;④D。
[例7-2] 链表不具备的特点是( )。
A.插入和删除不需要移动元素B.可随机访问任一结点
C.不必预分配空间D.所需空间与其长度成正比
解析:线性表可随机访问任一结点,而链表必须从第一个数据结点出发逐一查找每个结点。
本题答案为:B。
[例7-3] 不带头结点的单链表head为空的判定条件是( )。
A.head==NULL B.head_>next==NULL
C.head_>next==head D.head!=NULL
解析:在不带头结点的单链表head中,head指向第一个数据结点。
空表即该表没有结点,head==NULL表示该单链表为空。
本题答案为:A。
[例7-4] 带头结点的单链表head为空的判定条件是( )。
A.head==NULL B.head—>next==NULL
C.head—> next==head D.head!=NULL
解析:在带头结点的单链表head中,head指向头结点。
空表即该表只有头结点,head —>next==NULL表示该单链表为空。
本题答案为:B。
[例7-5] 带头结点的循环单链表head中,head为空的判定条件是( )。
A.head==NULL B.head—>next==NULL
C.head—> next==head D.head!=NULL
解析:在带头结点的循环单链表head中,head指向头结点。
空表即该表只有头结点,head—>next==head表示该单链表为空。
本题答案为:C。
[例7-6] 线性表采用链式存储时其存储地址( )。
A.必须是连续的B.部分地址必须是连续的
C.一定是不连续的D.连续不连续都可以
解析:链式存储采用动态存储,地址一般不连续。
本题答案为:D。
[例7-7] 在双向链表的* p结点前插入新结点*s的操作为( )。
A.p—>prior=s;s—>next=p;p—>prior—>next=s;s—>prior=p—>prior;
B.p—>prior=s;p—>prior—>next=s;s—>next=p;s—>prior=p—>prior;
C.s—>next=p;s—>prior=p—>prior;p—>prior=s;p—>prior—>next=s;
D.s—>next=p;s—>prior=p—>prior;p—>prior—>next=s;p—>prior=s;
解析:在双向链表的* p结点前插入新结点* s的操作如图7.12所示,图中虚线为所作的操作,序号为操作顺序。
本题答案为:D。
图7.12 双向链表插入结点的过程示意图
(例7-8)若某表最常用的操作是在最后一个结点后插入一个结点和删除第一个结点,则采用( )存储方式最节省运算时间。
A.单链表B.双向链表
C.给出表头指针的循环单链表D.给出尾指针的循环单链表
解析:在链表中插入或删除一个结点,需修改相邻结点的指针域。
上述四个选项中,只有选项D才能从尾指针经过最少的结点来进行题目要求的插入或删除操作。
本题答案为:D。
[例7-9] 若线性表中有2n个元素,算法( )在单链表上实现要比在顺序表上实现效率更高。
A.删除所有值为x的元素B.在最后一个元素的后面插入一个新元素C.顺序输出前k个元素D.交换其中某两个元素的值
解析:对于选项A,在单链表上和顺序表上实现的时间复杂度都为O(n),但后者要移动大量的元素,因此在单链表上实现效率更高。
本题答案为:A。
(例7-10) 在长度为n的( )上,删除第一个元素,其算法复杂度为O(n)。
A.只有表头指针的不带头结点的循环单链表
B.只有尾指针的不带表头结点的循环单链表
C.只有表尾指针的带头结点的循环单链表
D.只有尾指针的带表头结点的循环单链表
解析:本题答案为:A。
具体算法如下:
linklist * delfirst(linklist * h)
{
Linklist * p=h;
while(p—> next!=h) //找到表尾结点
p=p—>next;
p—>next=h—> next;
free(h);
returnp一>next;//返回头指针
}
二、填空题
[例7-11] 在单链表中结点* p后插入结点* s的指令序列为;。
解析:在单链表中结点* p后插入结点* s,即将* p 的后继结点变为* s 的后继结点,* s 则成为* p的后继结点。
操作指令序列为:s—>next=p—>next;p—>next=s。
[例7-12]在线性表的链式存储结构中,根据每个结点所含指针的个数,链表可分为和;而根据指针的链接方式,链表又可分为和。
解析:本题答案为:单链表;多重链表;循环链表;普通链表(非循环链表)。
[例7-13] 在单链表中,要删除某一个指定的结点,必须找到该结点的 结点。
解析:由单链表的特点可知,删除某一个结点的操作是将其前驱结点的next 指针域指 向该结点的后继结点。
本题答案为:前驱。
[例7-14] 在一个长度为n 的顺序表中删除第i(0≤i ≤n 一1)个元素,需向前移动 个元素。
解析:需将第i 个元素后的元素依次前移一个位置,总共移动(n-1)-(i+1)+1个元素。
本题答案为:n-i-1。
[例7-15] 在一个具有n 个结点的单链表,在 * p 结点后插入一个新结点的时间复杂度是 ;在给定值为x 的结点后插入一个新结点的时间复杂度是 。
解析:在 * p 结点后插入一个新结点 * s 的操作是:s —> next =p —> next ;p —>next = s ;其时间复杂度为0(1)。
在给定值为x 的结点后插入一个结点,首先要找到该结点,然后再进行插入。
找到该 结点的时间复杂度为O(n),插入的时间复杂度为O(1)。
本题答案为:O(1);O(n)。
三、应用题
(例7-16) 设A 是一个线性表(a 0,a 1,…,a i ,…,a n-1),采用顺序存储结构,则在等概率情况下平均每插入一个元素需要移动的元素个数是多少?若元素插在a i 和a i+1之间 (0≤i ≤n-1)的概率为1(1)/2
n n n -+,则平均每插入一个元素所需要移动的元素个数是多少?
解析:在等概率情况下,平均每插入一个元素需要移动的元素个数为:
(012)12
n n n ++++=+ 若元素插在a i 和a i+l 之间(0≤i ≤n-1)的概率为
(1)/2n i n n -+,则平均每插入一个元素所需 要移动的元素个数为:
10n i -=∑2222()221(1)1(1)/2(1)3
n i n n n n n n n -+⎡⎤=+-++=⎣⎦++ (例7-17) 简述线性表采用顺序存储方式和链式存储方式的优缺点。
解析:顺序表的优点是可以随机访问数据元素,而且不需要额外的空间存储元素间的逻辑关系;缺点是表的大小固定,增减结点需要移动大量元素。
链表的优点是增减元素非常方便,只需要修改指针内容;缺点是只能进行顺序访问,另外在每个结点上增加指针域会造成存储空间增大。
[例7-18] 若频繁地对一个线性表进行插入和删除操作,则应采用何种存储结构来存储该线性表?为什么?
解析:应采用链式结构来存储该线性表。
采用链式存储结构来存储线性表,在进行插 入和删除操作时的复杂度体现在查找插入或删除结点的前驱结点的操作上,查找过程中平 均移动指针域的次数为表长的一半;而采用顺序存储结构存储线性表,在进行插入和删除 操作时的复杂度则体现在元素的移动上,平均需移动表中的一半元素。
因为指针域的移动 操作次数比元素的移动操作次数少得多,所以应采用链式结构来存储该线性表。
(例7—19) (1)写出在双向链表中的结点 * p 前插入一个结点 *s 的语句序列。
(2)写出判断带头结点的双向循环链表L 为空表的条件。
解析:(1)s —>prior =p —>prior ;p —>prior — >next =s ;
s —>next =p ;p —>prior =s ;
(2)(L==L—>next)&&(L==L—>prior)
[例7-20] 链表所表示的元素是否是有序的?如果有序,则有序性体现在何处?链表所表示的元素是否一定要在物理上是相邻的?有序表的有序性又如何理解?
解析:链表所表示的元素是有序的,其有序性体现在逻辑有序,即指针有指向。
链表所表示的元素在物理上不一定相邻。
有序表的有序性不仅在逻辑结构上有序,而且在物理结构上也有序。
四、算法设计题
(例7-21)编写一个算法,将一个带头结点的单链表逆转。
要求在原链表空间上进行逆转,即不允许构造新的链表结点;
解析:从单链表的一种构造方法——头插法中可以得知,该方法构造的线性表中结点的顺序与插人次序相反。
因此我们可以将表结点从前往后逐个拆下并用头插法插人新表,所构造的单链表即为原表的逆转。
具体算法如下:
linklist * reverse(1inklist * h)
{
linklist * p,*q,*r;
p=h—>next;
h—>next=NULL;//构造空表
while(p!=NULL)
{
q=p;//拆下结点
p=p—> next;
q—>next=h—>next;//用头插法插入
h—>next=q;
}
return h;
}
(例7-22) 已知一个顺序表La的元素按值非递减有序,编写一个算法将元素x插人后保持该表仍然按值非递减有序。
解析:要让插入新元素后的顺序表仍然按值非递减有序,必须把x插入到表中第一个大于等于x的元素之前。
应先在表中找到该位置,然后后移该元素,空出一个位置,再将x 插入。
具体算法如下:
insert(sqlist *La,datatype x) //La为指向顺序表的指针
{
int i=0,j;
while(i<= La—>last) //查找插入位置i
{
if(x<=La—>data[i])
break;
i++;
}
for(j=La—>last+1;j>i;j--) //后移所有大于等于x的元素
La—>data[j]=La—>data[j-1];
La—>data[i]=x;//将x插入
La—>last++;//表长度加1
}
(例7-23)用顺序表A、B表示集合,编写算法求集合A和集合B的交集C(假设A、B 表内无重复元素)。
’
解析:求C=A∩B,C中元素是A、B中的公共元素。
对于表A中的每个元素,在表B中扫描,若有与它相同的元素,则为交集元素,将其放到C中。
具体算法如下:
intersection(sqlist A,sqlist B,sqlist * C)
{
int i,j,k=0;
for(i=0;i<=A.1ast;i++)
{
j=0;
while(j<=B.1ast&& A.dara[i]!=B.data[j]
j++;
if(j<=B.1ast) //表示A.data[i]在B中
C—>data[k++]=A.data[i]
}
C—>last=k—l;//修改表长度
}
[例7-24]编写一个算法,计算在头指针为head的单链表中数据域值为x的结点个数。
解析:先设一计数器n,初值为0。
然后遍历链表中的每个结点,每遇到一个结点都需要判断其数据域值是否为x,如果是,计数器n加1。
遍历完成后计数器n的值就是所求的结点数。
具体算法如下:
int count(linklist * head, datatype x)
{
int n=0;
linklist * p;
p = head;
while(p ! = NULL)
{
if(p—> data = = x)
n++;
p=p—>next;
}
return n;
}
(例7-25)用单链表La、Lb表示集合A、B,编写算法求集合A和集合B的差集C,并用链表Lc表示(假设A、B内无重复元素)。
解析:根据集合运算规则可知,集合A—B中包含所有属于集合A而不属于集合B的元素。
具体做法是:从头到尾扫描单链表La,并判断当前元素是否在单链表Lb中;若不
在,则将其插入单链表Lc中。
具体算法如下:
linklist * difference(linklist * La, linklist * Lb)
{
linklist *Lc, * pa, *pb, * s, * r;
pa= La—>next
Lc = (linklist * ) malloc (sizeof (linklist)) ;
r=Lc;
while(pa! = NULL)
{
pb=Lb—> next;
while (phb! = NULL & & pb—> data ! = pa—> data)
pb= pb—>next;
if(pb = = NULL)
{
s= (linklist * )malloe(sizeof(linklist));
s—> data= pa—>data;
r—>next=s;
r—s;
}
pa= pa—>next;
}
r—>next = NULL;
return Lc;
}
(例7-26) 已知两个头指针分别为La和Lb的单链表,它们的元素按值递增有序。
编写一算法将两个单链表合并,要求合并后链表仍然递增有序,不允许开辟另外的链表空间。
解析:由于题目要求不开辟另外的链表空间,所以首先以两个链表中的一个头结点为新链表的头结点构造一个空的单链表。
从头到尾逐个比较La和Lb表中的元素,将值较小的元素结点链接到新表的末尾,若结点值相同则将其中一个链接到新表的末尾而释放另一个。
当La或Lb为空后,把另一个链表余下的结点链接到新表的末尾。
具体算法如下:
linklist * union(linklist * La, linklist * Lb)
{
linklist * pa, * pb, * r;
pa = La—> next;
pb= Lb—>next;
r=La;//以*La为新表头结点,r为新表尾指针
free(Lb); //释放Lb表头结点
while(pa! =NULL && pb! =NULL)
{
if ( pa—> data< pb—> data)
{
r=pa;
pa= pa—>next;
}
else if(pa—>data<pb—>data)
{
r—> next = pb;
r=pb;
pb = pb—> next;
r—>next= pa;
}
else //pa->data = = Pb—>data的情况
{
r=pa;//将原La表结点插入,原Lb表结点删除
pa = pa—> next;
s=pb;
pb = pb—>next;
free(s);
}
}
if(pa==NULL) //将Lb表剩余结点链到新表
r—>next=pb;
return La;//返回新表头结点地址
}
(例7-27) 设计——个将循环双链表中结点*p与其后继结点交换位置的算法。
解析:本题应充分利用双向链表可对前驱结点和后继结点进行操作的特点。
具体算法如下:
int swap(dlinklist * p)
{
dlinklist * q;
if(p—>next= = p—>prior) //只有一个数据结点,不能交换
return 0;//交换失败
q=p—>next;//q指向* p的后继
p—>next=q—>next;//删除* q
q—>next—>prior= p;
q—>prior= p—>prior;//把*q插入*p前
q—>next=p;
p—>prior—>next=q;
p—>prior=q;
return 1;//交换成功
}
线性表习题
一单项选择题
1.下面关于线性表的叙述中,错误的是[]
A.线性表采用顺序存储,必须占用一片连续的存储单元。
B.线性表采用顺序存储,便于进行插入和删除操作。
C.线性表采用链接存储,不必占用一片连续的存储单元。
D.线性表采用链接存储,便于进行插入和删除操作。
2.带头结点的双向链表head为空的判定条件是[]
A.head==NULL
B.head->next==NULL
C.head->next==head
D.head!=NULL
3.若某线性表最常用的操作是存取任一指定序号的元素和在最后进行插入和删除运算,则利用[]存储方式最节省时间
A.顺序表 B.双链表 C 带头结点的双循环链表 D 单循环链表
4.链表不具有的特点是[]
A 插入和删除不需要移动元素
B 可随机访问任一元素
C 不必事先估计存储空间
D 所需空间与线性长度成正比
5.下面叙述中不正确的是[]
A 线性表在链式存储时,查找第i个元素的时间与i的值成正比
B线性表在链式存储时, 查找第i个元素的时间必须经过前i-1个元素
C 线性表在顺序存储时,查找第i个元素的时间与i的值成正比
D线性表在顺序存储时,查找第i个元素的时间与i的值无关
6对于顺序存储的线性表,访问结点和增加,删除结点的时间复杂度分别是
A O(n), O(n)
B O(n), O(1)
C O(1) O(n)
D O(1) O(1)
7 在一个以h为头指针的单循环链表中,p指针指向链尾的条件是
A p->next=h
B p->next=NULL
C p->next->next=h
D p->data=-1
8在单链表指针为p的结点之后插入指针为s的结点,正确的操作是
A p->next=s;s->next= p->next
B s->next= p->next; p->next=s
C p->next=s; p->next=s->next
D p->next=s->next; p->next=s
9 在双向链表存储结构中,删除p所指的结点时的操作是
A p->prior->next=p->next;p->next->prior=p->prior
B p->prior= p->prior->prior; p->prior->next=p
C p->next->prior=p; p->next= p->next->next
D p->next= p->prior->prior; p->prior= p->next->next
10 需要分配较大空间,插入和删除不需要移动元素的线性表,其存储结构是
A 单链表
B 静态链表
C 线性链表
D 顺序存储结构
11如果最常用的操作是取第i个结点及其前驱,则采用[]存储方式最节省时间
A 单链表
B 双链表
C 单循环链表
D 顺序表
12 在一个长度n(n>1)的单链表上设有头和尾两个指针,执行[]操作与链表
的长度有关
A 删除单链表中第一个元素结点
B删除单链表中最后一个元素结点
C 在单链表第一个元素结点前插入一个新结点
D 在单链表最后一个元素结点后插入一个新结点
13 与单链表相比,双链表的优点之一是
A插入和删除操作更简单 B 可以进行随机访问
C 可以省略头指针和表尾指针
D 访问相邻结点更灵活
14 设有两个长度为n的单链表,结点类型相同,若以h1为表头指针的链表是非循环链表,以h2为表头指针的链表是循环链表,则
A 对于两个链表来说,插入任意一个结点的操作,其时间复杂度是O(1) B对于两个链表来说,删除最后一个结点的操作,其时间复杂度是O(n)
C h2要比h1占用更多的存储空间
D h1和h2是不同类型的变量
二.判断题
1链表中的头结点仅起到标识的作用
2 顺序存储结构的主要缺点之一是不利于插入和删除操作
3 线性表采用链表存储时,结点和结点内部的存储空间可以是不连续的
4 顺序存储方式的插入和删除操作效率太低,因此它不如链式存储方式好
5 顺序存储方式只能用于存储线性结构
6 线性表的特点是每个元素都有一个前驱和一个后继
7 取线性表的第i个元素的时间同i的大小有关
8 线性表只能用顺序存储结构实现
9 顺序存储方式的优点是存储密度大,且插入和删除运算效率高
10 链表是采用链式存储结构的线性表,进行插入和删除操作时,一般在链表中比在顺序存储结构中的效率高
三.填空题
1 当线性表的元素总数基本稳定,且很少进行插入和删除操作,但要求以最快的速度存取线性表中的元素时,应采用[ ]存储结构。
2 线性表L=(a1,a2,…,an)用数组表示,若删除表中任一元素的概率相同,则删除一个元素平均需要移动元素的个数是[ ]
3 已知指针px指向单链表中数据域值为x的结点,指针py指向数据域值为y的新结点,若将结点y插入结点x之后,则需要执行以下语句:[ ]
4 在一个长度为n的顺序表中的第i个元素(0<=i<=n-1)之前插入一个新元素时,需向后移动[ ]个元素
5 对于一个具有n个结点的单链表,在已知的结点*p后插入一个新结点的时间复杂度为[ ],在给定值为x的结点后插入一个新结点的时间复杂度为[ ]
6 链接存储的特点是利用[ ]来表示数据元素之间的逻辑关系。
7 对于双向链表,在两个结点之间插入一个新结点需修改的指针共为[ ]个,而对于单链表则为[ ]个。
8循环单链表的最大特点是:[ ]
9 带头结点的双循环链表L中只有一个元素结点的条件是:[ ]
10 在单链表L中,指针p所指结点有后继结点的条件是:[ ]
11 将一个单链表中的*p结点删除,可执行如下操作:
q=p->next; p->data=p->next->data;
p->next=[ ];
free(q);。