1、,2.2 线性表,一、什么是线性表,二、线性表的顺序存储表示及其运算,三、线性表的链式存储表示及其运算,四、循环链表和双向链表,通常把线性表表示为:,称i为ai在线性表中的位序,一、什么是线性表,线性表是由n(n=0)个数据元素组成的有 限序列。,线性表中数据元素的个数n称为线性表 的长度,1、线性表的定义,一、什么是线性表,线性表中每个数据元素ai的具体含义,在 不同情况下各不相同,它可以是一个数, 或是一个符号,也可以是一页书,甚至是 其它更复杂的信息。但在同一个线性表中 的数据元素必须具有相同的特性(或者说具 有相同的类型)。,一、什么是线性表,下面给出几个线性表的例子:,例2-1 26
2、个大写的英文字母表:(A,B,C,.,Z),例2-2 一年中的四个季节(春、夏、秋、冬),例2-3 一个矩阵,8 10 6 9 4,一、什么是线性表,例2-4 某单位职工政治面貌登记表如表2-2所示, 每个职工的情况为一条记录,它由职工号、姓名、 性别、职称、工龄、政治面貌六个数据项组成。,在表2-2中,一个数据元素由若干个 数据项组成。在这种情况下,常把 数据元素称为记录,含有大量记录 的线性表又称为文件。,表2-2 职工政治面貌登记表,一、什么是线性表,一、什么是线性表,2、线性表的逻辑结构,非空线性表的逻辑结构特征:,(1)有且只有一个根结点a1,它无前驱,(2)有且只有一个叶子结点an
3、,它无后继,(3)除了根结点和叶子结点外,其他所有的结点有且只有一个直接前驱,也有且只有一个直接后继。,(2)各元素在存储空间中是按逻辑顺序依次存放的。,线性表的顺序存储结构具有的特点:,(1)所有元素所占的存储空间是连续的,线性表的起始地址,称作线性表的基地址,用一组地址连续的存储单元 依次存放线性表中的数据元素,二、线性表的顺序存储表示及其运算,1、线性表的顺序存储结构,所有数据元素的存储位置均可由该数据元素在线性表 中的位序唯一确定。,以“存储位置相邻”表示数据元素在线性表中 的次序关系(前驱和后继的关系),一个数据元素占据的存储量,基地址,二、线性表的顺序存储表示及其运算,可见,线性表
4、中每个元素的存储地址是该 元素在表中位序的线性函数。只要确定了 线性表的起始地址,线性表中任一数据元 素都可以随机存取,所以线性表的顺序存 储结构是一种随机存取的存储结构。,二、线性表的顺序存储表示及其运算,2、线性表的顺序存储表示,由于高级程序设计语言中,一维数组 的存储表示方法和上述线性表的顺序 存储表示相同,因此可以用C语言中 的一维数组来描述线性表的顺序存储 结构。,二、线性表的顺序存储表示及其运算,maxsize是线性表的最大长度,它可以根据实际 需要而修改。,其中,,二、线性表的顺序存储表示及其运算,线性表顺序存储的C语言表示,const int maxsize=10; struc
5、t sqlistET datamaxsize;/ET为数据元素的类型int len; ; /俗称顺序表,如果定义sqlist L; 则访问方式为:L.datai, L.len,在线性表L的第i个元素之前插入一个元素e,二、线性表的顺序存储表示及其运算,3、线性表在顺序存储下的运算,(1)插入运算,L=(a1,ai-1,ai,an),L=(a1,ai-1,e,ai,an),例1、在线性表(21,18,30,75,42,56,87)的第5个 元素之前插入一个新的元素66,二、线性表的顺序存储表示及其运算,其实施步骤为:,将第n至第i个元素后移一个存储位置;,(2) 将e插入到第i个位置;,(3)
6、线性表的长度加1。,56,42,66,87,75,30,18,21,二、线性表的顺序存储表示及其运算,例题中顺序表数据类型的C语言定义,const int maxsize=10; struct sqlistint datamaxsize;int len;/线性表数据元素的个数 ;,顺序表的初始化操作,二、线性表的顺序存储表示及其运算,void init(sqlist /置线性表初始元素个数为0 ,二、线性表的顺序存储表示及其运算,void create(sqlist ,创建含n个元素的顺序表,在顺序表的第i个元素之前插入元素e,void Insert(sqlist ,二、线性表的顺序存储表示及
7、其运算,(2)删除运算,L=(a1,ai-1,ai+1,an),L=(a1,ai-1,ai,ai+1,an),删除线性表L的第i个元素,例2,删除线性表(21,18,30,75,66,42,56,87) 的第5个元素。,二、线性表的顺序存储表示及其运算,87,56,42,75,30,18,21,56,42,66,87,75,30,18,21,具体实施步骤为:(1) 若i值合法,则将第i+1至第n个位置上的元素依次向前移动一个存储单位;(2) 将线性表的长度减1。,删除线性表L的第i个元素,void delet(sqlist ,从上述算法中不难看出,当在顺序存储 结构的线性表中某个位置上插入或删
8、除 一个数据元素时,其时间主要耗费在移 动元素上,而移动元素的个数取决于插 入或删除元素的位置。,二、线性表的顺序存储表示及其运算,在顺序存储的线性表中进行插入或删除操 作,平均要移动一半的元素,即T(n)=O(n) 当线性表的元素很多,且每个元素的数据 项较多时,花费在移动元素上的时间会很 长。一般情况下,线性表的顺序存储结构 适合于表中元素变动较少的线性表。,二、线性表的顺序存储表示及其运算,三、线性表的链式存储表示及其运算,1线性链表,线性表的链式存储结构的特点是用一组任意 的存储单元存储线性表中的数据元素,这组 存储单元可以是连续的,也可以是不连续的。 这样,逻辑上相邻的元素在物理位置
9、上就不 一定是相邻的,为了能正确反映元素的逻辑 顺序,就必须在存储每个元素ai的同时,存 储其直接后继元素的存储位置。,这时,存放数据元素的结点至少包括两个域, 一个域存放该元素的数据,称为数据域(data); 另一个域存放后继结点在存储器中的地址,称 为指针域或链域(next)。,三、线性表的链式存储表示及其运算,数据元素的结点结构如下:,三、线性表的链式存储表示及其运算,由n个结点的存储映像链接成的链表, 即为线性表的链式存储结构。,a1,a2,an,空指针,上述链表的每个结点中只包含一个指针域,故又称单链表或线性链表。,头指针,和顺序表类似,在链式存储结构中仍以第一个数据元 素的存储地址
10、作为线性表的基地址,通常称它为头指针,三、线性表的链式存储表示及其运算,可以用 C 语言中的“结构指针“来描述链表结构。,2线性链表的表示,若设 node *p,*q;,struct node ET data; struct node *next; ;,则 p,q 均为以上定义的指针型变量。, p-data 表示 p 所指结点中的数据域,p-next 表示 p 所指结点 中的指针域,若非空,则 其含义是指向后继结点的的起始地址。,三、线性表的链式存储表示及其运算,3线性链表的运算,(1) 初始化操作,void InitList(node* /不带头结点 ,判断不带头结点的链表是否为空: hea
11、d=NULL,调用:node* sq;InitList(sq);,三、线性表的链式存储表示及其运算,(2)、线性链表的查找元素,由于链表存储结构不是一种随机存取结构, 要查找单链表中的一个结点,必须从头指 针出发,沿结点的指针域逐个往后查找, 直到找到要查找的结点为止。,node* lookst (node* ,获取包含指定元素为e的前驱结点,三、线性表的链式存储表示及其运算,8,q=getpre(head,8),q,(3)、线性链表的插入,三、线性表的链式存储表示及其运算,线性链表的插入是指在链式存储结构下 的线性表中插入一个新的元素。为了要 在线性链表中插入一个新元素,首先要 给该新元素分
12、配一个新结点,以便用于存 储该元素的值。然后将存放新元素的结 点链接到线性链表中指定的位置。,三、线性表的链式存储表示及其运算,8,0,pnext=qnext;,qnext=p;,5,6,0,9,head,在头指针为head的链表中包含元素为e的结点前插入数据元素为b的结点,void insert(node* ,调用:node* sq;insert(sq,8,7);,(4) 线性链表的删除,三、线性表的链式存储表示及其运算,线性链表的删除是指在链式存储结构下的 线性表中删除包含指定元素e的结点。,三、线性表的链式存储表示及其运算,8,0,5,6,0,9,head,p,qnext=pnext;,
13、void Delete(node* ,在头指针为head的线性链表中删除数包含素为e的结点,调用:node* sq;Delete(sq,7);,三、线性表的链式存储表示及其运算,(5) 动态建立单链表的算法,要对单链表进行操作,首先要掌握怎样 建立单链表。链表是一种动态存储结构, 因此,建立线性表的链式存储结构的过 程就是一个动态生成链表的过程。即从 “空表”的初始状态起,依次建立各元素 结点,并逐个插入链表。,单链表建立方法一:正向建立单链表(尾插法)。,三、线性表的链式存储表示及其运算,思想:依次读入线性表的元素, 从前往后依次将元素插入到当 前链表的最后一个结点之后。,9,head,4,
14、5,q,P=new node; P-data=6; Pnext=NULL,0,qnext=p,正向建立链表,void create(node* ,正向创建包含n个结点的链表,调用:node* sq;create(sq,4);,三、线性表的链式存储表示及其运算,单链表建立方法二:逆向建立链表(头插法),思想:建表方法是从线性表的 最后一个元素开始,从后向前 依次插入到当前链表的第一个 结点之前。,4,5,6,0,P=new node; P-data=9;,pnext=head; Head=p;,逆向建立链表 CreateList (sq,4);,三、线性表的链式存储表示及其运算,void Cre
15、ateList(node* ,逆向创建包含n个结点的链表,调用:node* sq;createList (sq,4);,3、线性表的顺序存储结构和链式存储结构的区别,三、线性表的链式存储表示及其运算,顺序表和链表各自的优缺点,在实际应用中, 应根据具体问题的要求和性质来选择哪种存 储结构,主要从以下两个方面考虑:,(1)基于空间的考虑,当要求存储的线性表长度变化不大,易于事先 确定其大小时,为了节约存储空间,宜采用顺 序表;反之,当线性表长度变化大,难估计其 存储规模时,采用动态链表作为其存储结构为 好。,三、线性表的链式存储表示及其运算,(2)基于时间的考虑,若线性表的操作主要进行查找,很少
16、做插入 和删除操作时,采用顺序表作存储结构为宜; 反之,若需要对线性表进行频繁插入或删除 等操作时,宜采用链表做存储结构。,1双向链表,前面讨论的链式存储结构中只有一个指示直接 后继的指针域,所以从某结点出发只能顺指针 往后查找只能找到后件结点,但不能找到前件 结点。为克服链表这种单向性的缺点,为有更 大的灵活性来操作线性链表,可采用双向链表 存储结构。,四、循环链表和双向链表,在每个结点上增加另一个指向线性表中每个 元素的前趋结点的指针域prior,就得到双向 链表。其结点的结构如图所示。,双向链表结点结构,其中,prior是指向前趋结点的指针域; data是数据域;next是指向后继结点的
17、 指针域。,四、循环链表和双向链表,用 C 语言描述如下: struct DuLNode ElemType data; struct DuLNode *prior; struct DuLNode *next; ,p-prior-next = p p-next-prior = p,四、循环链表和双向链表,DuLNode *p;,2、循环链表,前面讨论的线性链表(没有带头结点) 对于插入和删除等操作对于空表和第一个元素必须单独考虑,致使空表和非空表操作不统一,为了克服这个缺点,可以采用循环链表结构。,四、循环链表和双向链表,循环单链表,四、循环链表和双向链表,循环单链表结构特点: 在表头增加了一个
18、头结点,循环链表的头结点指向表头结点。 循环链表中最后一个指针域不是空,而是指向表头结点。,在实际应用中,循环链表与线性单链表(不带 头结点)相比有两个优点:(1)只要指出表中任何一个结点的位置,就可以 从它出发访问其他所有的结点,而单链表做不 到这一点。 (2) 因为增加了头结点,使空表与非空表的运算 完全统一。,四、循环链表和双向链表,单链表(不带头结点)的运算:slink_3.cpp,循环链表的各种运算slink_2.cpp,作业:2.2、2.3、2.7、2.10,学习要求,1)、理解数据结构的概念,2)、牢记数据结构这门课程主要研究和讨论的三个方面的问题:,3)、了解线性表的逻辑结构特性,是顺序存储结构和链式存储结构。用前者 表示的线性表简称为顺序表,用后者表示 的线性表简称为链表。,4)、掌握在计算机中表示逻辑关系的两类不 同的存储结构,5)、熟练掌握这两类存储结构的描述方法以 及线性表的基本操作在这两种存储结构上的 实现。,学习要求,掌握顺序表、单链表(不带头结点)和循环链表的各种运算,6)、能够从时间和空间复杂度的角度综合 比较线性表两种存储结构的不同特点及其 适用场合。,学习要求,