数据结构ch02.docx
《数据结构ch02.docx》由会员分享,可在线阅读,更多相关《数据结构ch02.docx(21页珍藏版)》请在冰豆网上搜索。
![数据结构ch02.docx](https://file1.bdocx.com/fileroot1/2023-4/17/31797ff9-730d-450f-929f-a432e3ed1834/31797ff9-730d-450f-929f-a432e3ed18341.gif)
数据结构ch02
第2章线性表
2.1线性表的逻辑结构
2.1.1线性表的定义
线性表简称表,是零个或多个具有相同类型的数据元素的有限序列。
数据元素的个数定义为线性表的长度。
长度等于零时称为空表,一个非空表通常记为:
L=(a1,a2,……,an)。
相同类型的含义:
序列的含义:
线性表的示意图:
2.1.2线性表的抽象数据类型定义
线性表的抽象数据类型定义为:
ADTList
Data
线性表中的数据元素具有相同类型,相邻元素具有前驱和后继关系
将线性表抽象数据类型定义为抽象类:
Operation
InitList
前置条件:
线性表不存在
输入:
无
功能:
线性表的初始化
输出:
无
后置条件:
一个空的线性表
DestroyList
前置条件:
线性表已存在
输入:
无
功能:
销毁线性表
输出:
无
后置条件:
释放线性表所占用的存储空间
Length
前置条件:
线性表已存在
输入:
无
功能:
求线性表的长度
输出:
线性表中数据元素的个数
后置条件:
线性表不变
Get
前置条件:
线性表已存在
输入:
元素的序号i
功能:
在线性表中取序号为i的数据元素
输出:
若序号合法,返回序号为i的元素值,否则抛出异常
后置条件:
线性表不变
Locate
前置条件:
线性表已存在
输入:
数据元素x
功能:
在线性表中查找值等于x的元素
输出:
若查找成功,返回元素x在表中的序号,否则返回0
后置条件:
线性表不变
Insert
前置条件:
线性表已存在
输入:
插入位置i;待插元素x
功能:
在线性表的第i个位置处插入一个新元素x
输出:
若插入不成功,抛出异常
后置条件:
若插入成功,表中增加了一个新元素
Delete
前置条件:
线性表已存在
输入:
删除位置i
功能:
删除线性表中的第i个元素
输出:
若删除成功,返回被删元素,否则抛出异常
后置条件:
若删除成功,表中减少了一个元素
Empty
前置条件:
线性表已存在
输入:
无
功能:
判断线性表是否为空表
输出:
若是空表,返回1,否则返回0
后置条件:
线性表不变
PrintList
前置条件:
线性表已存在
输入:
无
功能:
按位置的先后次序依次输出线性表中的元素
输出:
线性表的各个数据元素
后置条件:
线性表不变
endADT
2.2线性表的顺序存储结构及实现
2.2.1线性表的顺序存储结构——顺序表
线性表的顺序存储结构称为顺序表。
说明:
1.顺序表是用一段地址连续的存储单元依次存储线性表的数据元素。
2.通常用一维数组来实现顺序表,C++中数组的下标从1开始。
3.线性表中第i个元素存储在数组(C++)中下标为i-1的位置。
4.顺序表的存储示意图:
5.设顺序表的每个元素占用c个存储单元,则第i个元素的存储地址为:
LOC(ai)=LOC(a1)+(i-1)×c
2.2.1顺序表的实现
将线性表的抽象数据类型定义在顺序表存储结构下用C++的类实现。
constintMaxSize=100;//100只是示例性的数据,可以根据实际问题具体定义
template//定义模板类SeqList
classSeqList
{
public:
private:
};
1.构造函数
顺序表类提供了两个构造函数。
无参构造函数SeqList():
创建一个空的顺序表,即将顺序表的长度初始化为0;
有参构造函数SeqList(Ta[],intn):
创建一个长度为n的顺序表,其操作过程如图2-3所示。
下面给出具体的构造函数。
2.插入
几点说明:
1.插入后,元素ai-1和ai之间的逻辑关系发生了变化并且存储位置要反映这个变化。
2.插入时,若在表尾插入,直接插入即可,否则元素必须是从最后一个元素开始移动,直至将第i个元素后移为止,然后将新元素插入位置i处。
(注意元素移动方向)
3.考虑插入时的边界条件:
如果表满了,则引发上溢异常;如果元素的插入位置不合理,则引发位置异常。
算法用伪代码描述如下:
具体的顺序表插入算法。
时间性能分析:
·最好情况:
·最坏情况:
·一般情况:
※结论:
3.删除
几点说明:
1.删除后元素ai-1和ai+1之间的逻辑关系发生了变化并且存储位置要反映这个变化。
2.删除时,若在表尾删除,直接删除即可,否则元素必须是从第i+1个元素(下标为i)开始移动,直至将最后一个元素前移为止。
(注意元素移动方向)
3.在移动元素之前要取出被删元素。
4.考虑删除时的边界条件:
如果表空,则引发下溢异常;如果元素的删除位置不合理,则引发位置异常。
算法用伪代码描述如下:
顺序表删除算法。
时间性能分析
·最好情况:
·最坏情况:
·平均情况:
※结论:
4.查找
⑴按位查找
显然,按位查找算法的时间复杂度为O
(1)。
⑵按值查找
按值查找算法的平均时间性能是O(n)。
顺序表小结:
·顺序表的优点:
⑴无需为表示表中元素之间的逻辑关系而增加额外的存储空间;
举例:
⑵可以快速地存取表中任一位置的元素。
举例:
·顺序表的缺点:
⑴插入和删除操作需移动大量元素。
原因:
⑵表的容量难以确定。
原因:
⑶造成存储空间的“碎片”。
原因:
2.3线性表的链接存储结构及实现
2.3.1线性表的链接存储结构——单链表
线性表的链接存储结构称为单链表。
结点结构为:
其中:
data:
数据域,存储
next:
指针域(亦称链域),存储
每个结点通过一个指针域将线性表的数据元素按其逻辑次序链接在一起,称为单链表。
用结构类型来描述单链表的结点:
template
structNode
{
Tdata;
Node*next;//此处也可以省略
开始结点:
终端结点:
头指针:
尾标志:
头结点:
};
线性表(a1,a2,a3,a4)的存储示意图如下:
2.3.2单链表的实现
将线性表的抽象数据类型定义在单链表存储结构下用C++中的类实现。
template
classLinkList
{
public:
private:
};
正确区分指针变量、指针、指针所指结点和结点的值概念:
1.按位查找
在单链表中查找第i个结点的算法用伪代码描述如下:
查找算法:
算法的时间复杂度为O(n)。
为什么?
在单链表中,即使知道被访问结点的位置i(即序号),也不能像顺序表那样直接按序号访问。
原因何在:
与顺序表按位查找比较,得到结论:
2.插入
注意分析在表头、表中间、表尾插入这三种情况,由于单链表带头结点,操作语句是一致的,不用特殊处理。
伪代码描述如下:
插入算法。
1.该算法的时间复杂度为多少?
为什么?
2.比较顺序表和单链表实现插入算法。
3.构造函数
有参构造函数LinkList(Ta[],intn),即生成一个有n个结点的单链表。
有两种方法:
头插法和尾插法。
⑴头插法
头插法是每次将新申请的结点插在头结点的后面,其执行过程如图2-13所示。
下面给出头插法建立单链表的算法。
头插法的特点:
⑵尾插法
尾插法就是每次将新申请的结点插在终端结点的后面,其执行过程如图2-14所示。
下面给出尾插法建立单链表的算法。
1.比较头插法和尾插法
2.分析两种算法的时间复杂度
3.它们各自适用范围
4.其它
4.删除
算法用伪代码描述如下:
下面给出具体的删除算法。
1.分析删除算法的时间复杂度
2.比较用顺序表和单链表实现删除算法
5.析构函数
单链表类中的结点是用运算符new申请的,在释放单链表类的对象时无法自动释放这些结点的存储空间,所以,析构函数应将单链表中结点的存储空间释放。
具体算法如下:
2.4顺序表和单链表的比较
2.4.1时间性能比较
所谓时间性能是指实现基于这种存储结构的基本运算(即算法)的时间复杂度。
2.4.2空间性能比较
所谓空间性能是指某种存储结构所占用的存储空间的大小。
2.5线性表的其它存储方法
2.5.1循环链表
在单链表中,如果将终端结点的指针域由空指针改为指向头结点,这种头尾相接的单链表称为单循环链表,简称循环链表。
为了使空表和非空表的处理一致,通常也附设一个头结点。
用头指针指示的循环链表,找到开始结点的时间是O
(1),找到终端结点的时间是O(n)。
若我们将头指针指示的循环链表改用指向终端结点的尾指针来指示循环链表,如图2-17所示,则查找开始结点和终端结点的时间都是O
(1),实际中多采用尾指针指示的循环链表。
2.5.2双链表
在单链表的每个结点中再设置一个指向其前驱结点的指针域,这样就形成了双链表。
单链表、单循环链表、双链表结点结构的比较:
·结点结构:
其中,data:
数据域,存放数据元素;
prior:
前驱指针域,存放该结点的前驱结点的地址;
next:
后继指针域,存放该结点的后继结点的地址。
可以用C++中的结构类型描述双链表的结点。
template
structDulNode
{
Tdata;
DulNode*prior,*next;
};
设指针p指向双循环链表中的某一结点,则双循环链表具有如下的对称性:
(p->prior)->next=p=(p->next)->prior
1.插入
在结点p的后面插入一个新结点s,需要修改四个指针:
①
②
③
④
注意指针修改的相对顺序。
在修改第②和③步的指针时,要用到p->next以找到p的后继结点,所以第④步指针的修改要在第②和③步的指针修改完成后才能进行。
2.删除
设指针p指向待删除结点,删除操作可通过下述两条语句完成:
①
②
2.5.3静态链表
静态链表是用数组来描述单链表,用数组元素的下标来模拟单链表的指针。
静态链表的每个数组元素由两个域构成:
data域存放数据元素,next域(也称游标)存放该元素的后继元素所在的数组下标。
由于它是利用数组定义的,属于静态存储分配,因此叫做静态链表。
解释游标:
静态链表上的插入和删除操作有什么特点:
2.5.4间接寻址
间接寻址是将数组和指针结合起来的一种方法,它将数组中存储数据元素的单元改为存储指向该元素的指针,如图2-24所示。
间接寻址的特点: