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