数据结构习题及答案与实验指导线性表2.docx

上传人:b****7 文档编号:25643831 上传时间:2023-06-11 格式:DOCX 页数:33 大小:76.66KB
下载 相关 举报
数据结构习题及答案与实验指导线性表2.docx_第1页
第1页 / 共33页
数据结构习题及答案与实验指导线性表2.docx_第2页
第2页 / 共33页
数据结构习题及答案与实验指导线性表2.docx_第3页
第3页 / 共33页
数据结构习题及答案与实验指导线性表2.docx_第4页
第4页 / 共33页
数据结构习题及答案与实验指导线性表2.docx_第5页
第5页 / 共33页
点击查看更多>>
下载资源
资源描述

数据结构习题及答案与实验指导线性表2.docx

《数据结构习题及答案与实验指导线性表2.docx》由会员分享,可在线阅读,更多相关《数据结构习题及答案与实验指导线性表2.docx(33页珍藏版)》请在冰豆网上搜索。

数据结构习题及答案与实验指导线性表2.docx

数据结构习题及答案与实验指导线性表2

第2章线性表

 

线性表是一种最基本、最常用的数据结构,它有两种存储结构——顺序表和链表。

本章主要介绍线性表的定义、表示和基本运算的实现。

重点讨论了线性表的存储结构,以及在顺序、链式两种存储结构上基本运算的实现。

重点提示:

●线性表的逻辑结构特征

●线性表的顺序存储和链式存储两种存储结构的特点

●在两种存储结构下基本操作的实现

2-1重点难点指导

2-1-1相关术语

1.线性表

线性表是具有相同数据类型的n(n≥0)个数据元素的有限序列,通常记为:

(a1,a2,…,an),其中n为表长,n=0时称为空表。

要点:

一种逻辑结构,其数据元素属于相同数据类型,之间的关系是线性关系。

2.顺序表

顺序存储的线性表。

要点:

按线性表中的元素的逻辑顺序依次存放在地址连续的存储单元里,其存储特点:

用物理上的相邻实现逻辑上的相邻。

3.链表

用链表存储的线性表。

要点:

链表是通过每个结点的链域将线性表的n个结点按其逻辑顺序链接在一起的,对每个结点的地址是否连续没有要求。

4.单链表

每个结点除了数据域外还有一个指向其后继的指针域。

要点:

通常将每个元素的值和其直接后继的地址作为一个结点,通过每个结点中指向后继结点的指针表示线性表的逻辑结构。

5.头指针

要点:

头指针是一个指针变量,里面存放的是链表中首结点的地址,并以此来标识一个链表。

如链表H,链表L等,表示链表中第一个结点的地址存放在指针变量H、L中。

通常用头指针来惟一标识一个链表。

6.头结点

要点:

附加在第一个元素结点之前的一个结点,头指针指向头结点。

当该链表表示一个非空的线性表时,头结点的指针域指向第一个元素结点;为空表时,该指针域为空。

7.头结点的作用

要点:

其作用有两个,一是使对空表和非空表的处理得到统一;二是在链表的第一个位置上的操作和在其他位置上的操作一致,无需特殊处理。

2-1-2线性表的顺序存储

1.顺序表

顺序存储的线性表称为顺序表。

其特点是:

用一组地址连续的存储单元来依次存放线性表的数据元素,因此数据元素的逻辑顺序和物理次序一致(这是顺序存储的核心所在)。

具体实现:

在程序设计语言中,一维数组在内存中占用的存储空间就是一组连续的存储区域,因此,用一维数组来表示顺序表的数据存储区域是再合适不过的。

考虑到线性表的运算有插入、删除等,即表长是可变的,因此,数组的容量需设计得足够大,设用data[MaxSize]来表示,其中MaxSize是一个根据实际问题定义的足够大的整数,线性表中的数据从data[0]开始依次顺序存放,但当前线性表中的实际元素个数可能未达到MaxSize个,因此需用一个变量last记录当前线性表中最后一个元素在数组中的位置,即last起一个指针的作用,始终指向线性表中最后一个元素,因此,表空时last=-1。

这种存储思想的具体实现可以是多样的。

方法一:

可以用一个数组和表示长度的变量共同完成上述思想,如:

#defineMaxSize……//MaxSize为根据实际问题定义的足够大的整数

DataTypedata[MaxSize];

intlast;

这样表示的顺序表如图2-1所示。

数据元素分别存放在data[0]到data[last]中。

这样使用简单方便,但有时不便管理。

图2-1线性表的顺序存储示意图

方法二:

从结构上考虑,通常将data和last封装成一个结构作为顺序表的类型:

#defineMaxSize……//MaxSize为根据实际问题定义的足够大的整数

typedefstruct{

DataTypedata[MaxSize];

intlast;//表示线性表最后一个元素位置。

}SeqList;

定义一个顺序表变量:

SeqListL;

这样表示的线性表如图2-2(a)所示。

表长为L.last+1,线性表中的数据元素a1~an分别存储在L.data[0]~L.data[L.last]中。

方法三:

由于教科书中的算法用VisualC++语言描述,根据VisualC++语言中的一些规则,有时定义一个指向SeqList类型的指针更为方便:

SeqList*L;

L是一个指针变量,线性表的存储空间通过L=newSeqList操作(VisualC++语句,不同的语言版本可能有所不同)来获得。

L中存放的是顺序表的地址,这样表示的线性表如图2-2(b)所示。

表长表示为(*L).last+1或L->last+1,线性表中数据元素的存储空间为:

L->data[0]~L->data[L->last]。

读者通过上述介绍的几种表示方式,进一步体会顺序存储的“理念”,做题时根据题意灵活掌握,在读写算法时注意相关数据结构的类型说明。

(b)表长为L->last+1

(a)表长为L.last+1

6

6

L.last5

L->last5

L->length6

a6

a5

a4

a3

a2

a1

a6

a5

a4

a3

a2

a1

0

3

2

4

1

5

MaxSize-1

MaxSize-1

3

4

5

2

1

0

L->data

L.data

图2-2线性表的顺序存储示意图

2.顺序表的优缺点

优点1:

顺序表是由地址连续的向量实现的,因此具有按序号随机访问的特点。

设a1的存储地址为Loc(a1),每个数据元素占d个存储地址,则第i个数据元素的地址为:

Loc(ai)=Loc(a1)+(i-1)*d1≤i≤n

这就是说只要知道顺序表首地址和每个数据元素所占地址单元的个数就可求出第i个数据元素的地址来,这就是顺序表具有按数据元素的序号随机存取的特点。

优点2:

存储密度高。

缺点1:

在顺序表中做插入和删除运算时,平均需移动大约表中一半的元素;

缺点2:

顺序表的存储空间是静态分配的,在程序执行之前必须明确规定它的存储规模,因此分配不足则会造成溢出;分配过大,又可能造成存储单元的浪费。

2-1-3链表

1.单链表

图2-3单链表结点结构

链表是通过一组任意的存储单元来存储线性表中的数据元素的,为建立起数据元素之间的线性关系,对每个数据元素ai,除了存放数据元素自身的信息ai之外,还需要和ai一起存放其后继ai+1所在的存储单元的地址,这两部分信息组成一个“结点”,结点的结构如图2-3所示,每个元素都如此。

因此n个元素的线性表通过每个结点的指针域拉成了一个“链子”,称之为链表。

因为每个结点中只有一个指向后继的指针,所以称其为单链表。

链表是由一个个结点构成的,结点定义如下:

typedefstructNode{

DataTypedata;

structNode*next;

}LNode,*LinkList;

LNode是结点的类型,*LinkList是指向LNode结点的指针类型。

作为线性表的一种存储结构,我们关心的是结点间的逻辑结构,而对每个结点的实际地址并不关心,所以通常的单链表用图2-4的形式表示。

图2-4单链表

通常用“头指针”来标识一个单链表,如单链表L、单链表H等,是指某链表的第一个结点的地址放在了指针变量L、H中,头指针为“NULL”则表示一个空表。

2.单循环链表

对于单链表而言,最后一个结点的指针域是空指针,如果将该链表的头指针置入该指针域,则使得链表头尾结点相连,就构成了单循环链表。

对于单链表只能从头结点开始遍历整个链表,而对于单循环链表则可以从表中任意结点开始遍历整个链表,不仅如此,有时对链表常做的操作是在表尾、表头进行,此时可以改变一下链表的标识方法,不用头指针而用一个指向尾结点的指针R来标识,可以使操作效率得以提高。

3.双向循环链表

图2-5双向链表

在单链表的结点中只有一个指向其后继结点的指针域next,因此若已知某结点的指针为p,其后继结点的指针则为p->next,而找其前驱结点则只能从该链表的头指针开始,顺着各结点的next域进行,也就是说找后继结点的时间性能是O

(1),找前驱的时间性能是O(n),如果希望找前驱结点的时间性能也达到O

(1),则只能付出空间的代价:

每个结点再加一个指向前驱结点的指针域,结点的结构如图2-5所示,用这种结点组成的链表称为双向链表。

双向链表结点及指针类型定义如下:

typedefstructDLNode{

DataTypedata;

structDLNnode*prior,*next;

}DLNode,*DLinkList;

和单链表类似,双向链表通常也是用头指针标识。

通过双向链表中某结点的指针p既可以直接得到它的后继结点的指针p->next,也可以直接得到它的前驱结点的指针p->prior。

这样在有些操作中需要找前驱结点时,则勿需再用循环。

设p指向双向循环链表中的某一结点,即p中是该结点的指针,则p->prior->next表示的是p所指结点之前驱结点的后继结点的指针,即与p相等;类似,p->next->prior表示的是p所指结点之后继结点的前驱结点的指针,也与p相等,所以有以下等式:

p->prior->next=p=p->next->prior

4.静态链表

静态链表是指以数组方式存放链表的数据,数组的每个元素包含有数据域data和指针域next,这里的指针域next与链表中的指针域不同的是其存放的是该结点逻辑上的后继结点的相对地址(即在数组中的下标),也称之为静态指针。

在以静态链表方式存储链表时,数组中含有两个单链表,一个是数据元素的链表,一个是空结点的链表,故还需要设置两个整型变量,分别用于存放链表首元素(或头结点)在数组中的位置和空结点链表的首位置。

静态链表存储定义如下:

#defineMAXSIZE……//足够大的数

typedefstruct{

DataTypedata;

intnext;

}SNode;//结点类型

SNodesd[MAXSIZE];//数组sd以静态链表方式存放链表数据

intSL,AV;//两个头指针变量

5.链式存储的优缺点

链式存储的优缺点与顺序存储互补:

优点1:

对链表做插入和删除运算时,只需改变指针,不需移动数据。

优点2:

不需要事先分配空间,便于表的扩充。

缺点1:

存储密度降低,因为每个结点中除了存放数据元素的值还有一个指针域。

缺点2:

不具有按序号随机访问第i个元素的特点,必须通过标识链表的头指针(或尾指针)“顺藤摸瓜”才能找到第i个结点。

2-1-4线性表的基本运算

1.基于顺序表的运算

顺序表中常做的运算有插入、删除、合并、查找等,做这些运算时,要掌握一个原则:

时刻体现顺序存储的思想,即元素之间物理相邻和逻辑相邻的一致性。

(1)在顺序表中插入元素:

①插入元素时,检查顺序表是否已满,已满则不能做插入操作。

②根据具体问题确定插入位置。

③移动有关元素,以便为待插入的元素让出位置来。

④将元素插入。

⑤修改表长。

(2)在顺序表中删除元素:

①检查顺序表是否已空,空则不能做删除运算。

②根据具体问题确定删除元素的位置。

③将其后面的有关元素移动,“挤掉”被删除的元素。

④修改表长。

结论:

顺序表中插入一个数据元素平均需要移动(n+1)/2个元素。

具体某一次的插入中,移动数据元素的个数与表长和插入位置有关。

顺序表中删除一个数据元素需要平均移动n/2个元素。

具体某一次的删除中,移动数据元素的个数与表长和删除元素的位置有关。

2.基于链表的运算

链表操作过程中,主要是指针的变化,因此必须清楚指针和动态结点的问题。

(1)头结点的使用

在对不带头结点的单链表进行操作时,对第一个结点的处理和其他结点是不同的。

头结点的加入完全是为了运算的方便,它的数据域无定义,指针域中存放的是第一个数据元素结点的地址,空表时为空。

(2)插入

①后插结点:

设指针p指向单链表中某结点,s指向待插入的值为x的新结点,将s结点插入到p结点的后面,插入示意图如图2-6所示。

操作如下:

s->next=p->next;

p->next=s;

要点:

两个指针的操作顺序不能交换。

②前插结点

设指针p指向链表中某结点,s指向待插入的值为x的新结点,将s结点插入到p结点的前面,插入示意图如图2-7所示,与后插不同的是:

首先要找到p结点的前驱结点q,然后再完成在q结点之后插入s结点的操作,设单链表头指针为L,操作如下:

q=L;

while(q->next!

=p)

q=q->next;//找p的直接前驱

s->next=q->next;

q->next=s;

图2-6在p之后插入s图2-7在p之前插入s

后插操作的时间复杂性为O

(1),前插操作因为要找p结点的前驱结点,时间性能为O(n);其实我们更关心的是数据元素之间的逻辑关系,所以仍然可以将s结点插入到p结点的后面,然后将p->data与s->data交换即可,这样既满足了逻辑关系,也能使得时间复杂性为O

(1)。

由此得知:

在单链表中插入一个结点必须知道其前驱结点。

③在单链表第i个元素之前插入元素x

ⅰ.从头指针开始找到第i-1个元素结点,若存在继续步骤ⅱ,否则结束。

ⅱ.申请、填装新结点。

ⅲ.将新结点插入,结束。

(3)删除

①删除结点

ⅰ.删除p结点的后继结点(假设存在),则可以直接完成:

s=p->next;

p->next=s->next;

deletes;

该操作的时间复杂性为O

(1)。

ⅱ.若要删除p结点,即p所指结点,通过示意图可见,要实现对结点p的删除,首先要找到p结点的前驱结点q,然后完成指针的操作即可。

指针的操作由下列语句实现:

q->next=p->next;

deletep;

显然找p结点前驱结点的时间复杂性为O(n)。

图2-8删除p结点

操作示意图如图2-8所示。

当p结点有后继结点时,对p结点的删除可以这样处理:

把结点p后继结点的值存储到结点p中,再删除结点p的后继结点,这样逻辑上删除了p结点,而时间性能为O

(1)。

②删除单链表的第i个结点

在单链表中删除第i个结点,必须知道第i-1个结点的指针。

算法思路:

ⅰ.找到第i-1个结点;若存在继续步骤ⅱ,否则结束。

ⅱ.若存在第i个结点则继续步骤ⅲ,否则结束。

ⅲ.删除第i个结点,结束。

(4)查找

在单链表中按值查找或按序号查找某个元素,需通过头指针从第一个元素结点开始,逐个与x进行比较或记数,若查找成功,则返回指向该元素的指针,若查找失败,则返回NULL。

(5)双向链表中结点的插入

图2-9双向链表中的结点插入

设p指向双向链表中某结点,s指向待插入的值为x的新结点,将*s所指结点插入到*p所指结点的前面,插入示意图如图2-9所示。

操作如下:

①s->prior=p->prior;

②p->prior->next=s;

③s->next=p;

④p->prior=s;

指针操作的顺序不是惟一的,但也不是任意的,操作①必须要放到操作④的前面完成,否则结点p的前驱结点的指针就丢掉了。

读者把每条指针操作的涵义搞清楚,就不难理解了。

图2-10双向链表中结点的删除

(6)双向链表中结点的删除

设p指向双向链表中某结点,删除指针p所指结点。

操作示意图如图2-10所示。

操作如下:

①p->prior->next=p->next;

②p->next->prior=p->prior;

deletep;

2-2典型例题解析

2-2-1选择题

1.带头结点的单链表head为空的判断条件是()。

A.head==NULLB.head->next==NULL

C.head->next==headD.head!

=NULL

【分析】链表为空时,头结点的指针域为空。

【答案】B

2.若某线性表中最常用的操作是在最后一个元素之后插入一个元素和删除第一个元素,则采用()存储方式最节省运算时间。

A.单链表B.仅有头指针的单循环链表

C.双链表D.仅有尾指针的单循环链表

【分析】根据题意要求,该线性表的存储应能够很方便地找到线性表的第一个元素和最后一个元素,A和B都能很方便地通过头指针找到线性表的第一个元素,却要经过所有元素才能找到最后一个元素;选项C双链表若存为双向循环链表,则能很方便地找到线性表的第一个元素和最后一个元素,但存储效率要低些,插入和删除操作也略微复杂;选项D可通过尾指针直接找到线性表的最后一个元素,通过线性表的最后一个元素的循环指针就能很方便地找到第一个元素。

【答案】D

3.线性表的静态链表存储结构与顺序存储结构相比优点是()。

A.所有的操作算法简单B.便于插入和删除

C.便于利用零散的存储器空间D.便于随机存取

【分析】静态链表采用的是链式方式存储线性表,因此其具有链式存储的特点。

【答案】B

4.若长度为n的线性表采用顺序存储结构,在其第i个位置插入一个新元素算法的时间复杂度为()。

A.O(log2n)B.O

(1)

C.O(n)D.O(n2)

【分析】在第i个位置上插入新元素需要从最后一个元素开始后移直到第i个元素后移为止,后移元素的次数为n-i+1,即时间复杂度为O(n)。

【答案】C

5.将两个各有n个元素的有序表归并成一个有序表,其最少的比较次数是()。

A.nB.2n-1C.2nD.n-1

【分析】当一个表的最小元素大于另一个表的最大元素时比较次数为最少,共需n次。

【答案】A

6.在双循环链表p所指结点之后插入s所指结点的操作是()。

A.p->next=s;s->prior=p;p->next->prior=s;s->prior=p->next;

B.p->next=s;p->next->prior=s;s->prior=p;s->next=p->next;

C.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;

【分析】由于要将s所指结点插入到p所指结点之后,p结点为s结点的前驱,s结点为p结点的新后继,而结点p的原后继结点为结点s的后继结点,结点s为结点p的原后继结点的前驱结点。

在选项A、B和C中均是先执行操作p->next=s,就是修改了结点p的后继结点为s结点,然后再执行操作p->next->prior=s,因此,无法使得结点s为结点p的原后继结点的前驱结点,这样的赋值会使s结点为其自身的前驱。

应先执行操作p->next->prior=s,再执行操作p->next=s。

【答案】D

7.在一个单链表中,已知q所指结点是p所指结点的前驱结点,若在q结点和p结点之间插入s结点,则执行()

A.s->next=p->next;p->next=s;

B.p->next=s->next;s->next=p;

C.q->next=s;s->next=p;

D.p->next=s;s->next=q;

【分析】由于是将s所指结点插入到q和p所指结点之间,即使其为q所指结点的后继结点,为p所指结点的前驱结点,因此s->next的取值应为p,p->next的取值无需改动,q->next的取值应改为s,故A、B和D均是错误的。

【答案】C

2-2-2判断题

1.顺序存储的线性表可以按序号随机存取。

【分析】因为顺序表在内存是用地址连续的空间存储的,设a1的存储地址为Loc(a1),每个数据元素占d个存储地址,则第i个数据元素的地址为:

Loc(ai)=Loc(a1)+(i-1)*d1<=i<=n

这就是说只要知道顺序表首地址和每个数据元素所占地址单元的个数就可求出第i个数据元素的地址来,这也是顺序表具有按数据元素的序号随机存取的特点。

【答案】正确

2.在单链表中和在顺序表中插入一个元素其时间复杂度均为O(n),因此说它们的执行时间是相等的。

【分析】大O记法表示时间渐近复杂度,是指一个算法中的时间耗费,往往是问题规模n的函数T(n),当n趋向于无穷大时,T(n)的数量级称为算法的时间渐近复杂度。

虽然两种存储结构下的插入操作时间复杂度均为O(n),但由于两者的基本操作不同,因此不能说它们的执行时间是相等的。

【答案】错误

3.静态链表既有顺序存储的优点,又有动态链表的优点。

所以,它存取表中第i个元素的时间与i无关。

【分析】因为静态链表的存取特性与动态链表是一样的,只能顺序地找到第i个元素,不能随机地存取第i个元素,故其存取表中第i个元素的时间与i有关。

【答案】错误

2-2-3简答题

1.如图所示的双向链表中,欲在结点p前插入一个结点s,请完成有关操作。

s->prior=p->prior;

p->prior=s;

______________________

s->next=p;

【解答】

只能是:

s->prior->next=s;而不能为:

p->prior->next=s;

因为在上面的第二条语句中已经改变了结点p的前驱结点,结点p的前驱结点已经为s结点,而不是操作前的前驱结点了。

在下面的语句顺序下,可有两个答案的选择。

s->prior=p->prior;

______________________

p->prior=s;

s->next=p;

读者做这种题时,最好予以图示,不易出错。

2.已知线性表非递减有序,存储于一个一维数组A[0..n-1]中(表长为n,设为全局量),下面算法的功能是什么?

voiddel(DataTypeA[]){

inti,j;

i=1;

while(i<=n-1)

if(A[i]!

=A[i+1])

i++;

else{

for(j=(i+2);j

A[j-1]=A[j];

n--;

}

}

【解答】

由于一维数组中的元素按元素非递减有序排列,值相同的元素必为相邻的元素,因此依次比较相邻两个元素,若值相等,则删除其中一个,否则继续向后查找。

故算法功能是删除一维数组中多余的值相同的元素。

3.下述算法的功能是什么?

LinkListDemo(LinkListL){

//L是无头结点的单链表

LNode*q,*p;

if(L&&L->next){

q=L;

L=L->next;

p=L;

while(p->next)

p=p->next;

p->next=Q;

q->next=NULL;

}

returnL;

}

【解答】

算法的功能是把单链表的第一个结点从表头移到了链尾。

返回的L指向原链表的第二个结点。

若原链表表示的线性表是(a1,a2,…,an),则操作后表示的线性表为(a2,a3,…,an,a1)。

4.试描述头指针、头结点、开始结点的区别,并说明头指针和头结点的作用。

【解答】

头指针是一个指针变量,里面存放的是链表中首结点的地址,并以此来标识一个链表。

如链表H,链表L等,表示链表中第一个结点的地址存放在H、L中。

头结点是

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 医药卫生 > 基础医学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1