1、2018/9/6,1,教学目的:掌握线性表的概念和类型定义 教学重点:线性表的顺序存储结构和链式存储结构 教学难点:链表的操作,第2章 线性表,2018/9/6,2,线性表(Linear list)是最简单且最常用的一种数据结构。这种结构逻辑上具有下列特点:存在一个唯一的没有前驱的数据元素称为表头 ;存在一个唯一的没有后继的数据元素称为表尾 ;其它数据元素均有且仅有一个直接前驱和一个直接后继.,本章学习导读,2018/9/6,3,1.线性表的概念和类型定义 2.线性表的顺序存储结构及算法实现 3. 补充: C语言中结构体操作 教学重点:线性表的插入、删除操作,本课内容,2018/9/6,4,线
2、性表由一组具有相同属性的数据元素构成。数据元素的含义很广泛,在不同的具体情况下,可以有不同的含义。1 . 线性表的定义 线性表L是n(n0)个具有相同属性的数据元素a1,a2,a3,an组成的有限序列,其中序列中元素的个数n称为线性表的长度。当n=0时称为空表,即不含有任何元素。,2.1 线性表的基本概念,2018/9/6,5,例1、26个英文字母组成的字母表(A,B,C、Z) 例2、从1978年到1983年各种型号的计算机拥有量的变化情况。 (6,17,28,50,92,188) 例3、学生统计表,2018/9/6,6,从以上例子可看出,线性表的特点: (1)有穷性:线性表长度是有限的; (
3、2)有序性:元素之间是有顺序限制的,并且用直接前驱和后继来描述; (3)同型性:所有元素是同一数据类型; (4)抽象性:数据元素的类型没有具体定义,只是给出一个抽象说明(DataType)。即可以是简单类型,也可以是复杂的构造类型; (5)原子性:数据元素整体上作为一个独立的存储对象,不再分解为更小的数据单位进行存储。,2018/9/6,7,2.2 线性表的顺序结构及实现,线性表的顺序存储结构可以有静态结构和动态结构两种不同的方式。顺序存储结构的特点:在内存中用地址连续的存储单元按照数据元素的逻辑顺序、依次“一个接一个”地存放线性表的所有数据元素,通过物理位置的相邻来表示元素之间的逻辑关系。,
4、所谓静态结构指:线性表所占的存储空间是在编译时就确定的,且一经分配不再改变。动态结构指:线性表所需的存储空间可以在运行时分配, 并且能够根据需要增加或释放。,2018/9/6,8,线性链的基本操作,创建一个线性表 向表中插入一个元素 删除一个元素 获取指定元素 求链表长度 输出链表所有元素,2018/9/6,9,在具体实现时,一般用高级语言中的数组来对应连续的存储空间。设最多可存储MaxLen个元素,在C语言中可用数组dataMaxLen来存储数据元素,为保存线性表的长度需定义一个整型变量length。线性表的第l,2,n个元素分别存放在此数组下标为0,1,length-1数组元素中,如下图所
5、示,2018/9/6,10,一个线性表的顺序存储结构需要两个分量描述,为体现数组data和length之间的内在联系,通常将它们定义在一个结构类型中。 可用下述类型sqList定义来描述顺序表(重点):,#define MaxLen 100 /线性表的容量typedef struct DataType dataMaxLen; /定义存储表元素的数组int length; /线性表的实际长度 sqList;typedef int DataType /元素类型DataType简化为int型,2.2.1 线性表的顺序静态结构及实现,2018/9/6,11,1初始化表操作的实现顺序表的元素存储空间是数
6、组(空间已经静态分配),因此初始化只要将结构sqList结构中的表长度置0,就可以实现建空表的功能。void InitList( sqList *L) L- length=0; 调用:sqList List1; /定义结构体变量InitList(&List1) /初始化该表注意与教材p21算法的调用区别,2.2.1 线性表的顺序静态结构及实现,2018/9/6,12,1初始化表操作的实现顺序表的元素存储空间是数组(空间已经静态分配),因此初始化只要将结构sqList结构中的表长度置0,就可以实现建空表的功能。sqList* InitList() sqList *L;L=(sqList *)ma
7、lloc(sizeof(sqList); /创建表结点L- length=0; /置表长 调用方法:sqList *List1; /定义指针变量List1=InitList() /初始化该表,2.2.1 线性表的顺序静态结构及实现,2求线性表长度GetLen(L)的实现求线性表的长度算法如下:int Getlen(sqList *L) return L-length;该算法的时间复杂度为O(1),2018/9/6,13,2.2.1 线性表的顺序静态结构及实现,2018/9/6,14,3按序号取元素GetElem(L,i)的实现按前面的约定,序号为i的元素存储在数组下标为i-1的数组元素中,所以
8、可直接从该数组元素中取得值。i的有效值应大于等于1和小于等于线性表的实际长度。DataType GetElem(sqLlist *L,int i) if(iL-length) /*判断参数是否合法*/ printf(“error”);exit(1);return L-datai-1;,2.2.1 线性表的顺序静态结构及实现,2018/9/6,15,5顺序表的插入算法(重点)顺序表的插入是指在表的第 i个位置上插入一个值为 x的新元素,插入后使原表长为 n的表 (a1,a2, ,ai-1,ai,ai+1, ,an)成为表长为 n+1的线性表需要注意的是:插入后形成的新表必须保持原来的特点:逻辑上
9、相邻的物理也相邻.,2.2.1 线性表的顺序静态结构及实现,2018/9/6,16,例:在线性表(a1,a2,ai-1,ai,ai+1,an )第 i个位置插入x (i的取值范围为1in+1 ):,序号 元素,序号 元素,插入x,插入前,插入后,2018/9/6,17,插入算法步骤描述:1.判断参数i是否合法,合法则继续2.判断表是否已满,若满则退出3.由最后一个元素开始依次将第i个位置后的元素后移4.将新元素保存到第i个位置5.修改线性表长度(增1),2.2.1 线性表的顺序静态结构及实现,2018/9/6,18,算法描述: void InsertElem(sqList *L,int i,D
10、ataType x) if (iL-length+1) printf(“Error!”) ; /插入位置出错 exit(1); if(L-length=MaxLen) printf(“overflow!”) ; /表已满 exit(1); for(j=L-length;j=i;j-)L-dataj=L-dataj-1; /数据元素后移 L-datai-1=x; /插入x L-length+; /表长度加1 ,2.2.1 线性表的顺序静态结构及实现,2018/9/6,19,假设表中任何位置插入概率是均等的,即Pi=1/ (n+1) ,则:,插入算法分析: 该算法的时间主要花费在移动数据元素上,移
11、动次数取决于插入位置 i和表的长度n。所以用数据元素的移动操作来估计算法的时间复杂度。在第 i个位置上插入 x ,共需要移动 n-i+1个元素, i 的取值范围为 :1i n+1,即有 n+1个位置可以插入。由于插入的位置是随机的,因此需要分析执行该算法移动数据元素的平均值。设在第i个位置上插入的概率为Pi,则平均移动数据元素的次数为:,结论:线性表的插入操作平均要移动一半的元素,时间复杂度为(n)。,2018/9/6,20,6顺序表的删除运算DeleElem(L,i)的实现顺序表的删除运算是指将表中第 i 个元素从线性表中去掉.对表长为 n 的线性表:(a1,a2, ,ai-1,ai,ai+
12、1,an) ,进行删除操作后变为表长n-1的表(a1,a2, ,ai-1,ai+1, ,an),i 的取值范围为:1in 。,2.2.1 线性表的顺序结构及实现,2018/9/6,21,图2-5 线性表中的删除运算示意图,2018/9/6,22,算法实现:,(1) 将第i个至第n个元素(共n-i+1个元素)依次向前移动一个位置,将所删除的元素ai覆盖掉,从而保证逻辑上相邻的元素物理位置也相邻。 (2)修改线性表长度,使其减1。线性表的删除算法如下:void Delelem(sqList *L,int i) /删除线性表中第i个位置上的元素 if (iL-length) /检查空表及删除位置的合
13、法性 printf (不存在第i个元素);exit(0); for(j=i;jlength-1;j+)L-dataj-1=L-dataj; /向前移动元素L-length-; ,2.2.1 线性表的顺序结构及实现-删除算法,2018/9/6,23,删除算法的时间性能分析:与插入运算相同,删除运算的时间也主要消耗在移动表中数据元素上,删除第i个元素时,其后面的元素 ai+1an 都要向前移动一个位置,共移动了 n-i 个元素,所以在等概率的情况下,在线性表中删除数据元素所需移动数据元素的期望值,即平均移动数据元素的次数为:,由此可以看出,在线性表上删除数据元素时大约需要移动表中一半的元素,显然该
14、算法的时间复杂度为(n)。,通常情况下,我们认为在线性表中任何位置删除元素是等概率的,即pi =1/ n,则:,2018/9/6,24,线性表的动态分配顺序结构类型SqList定义如下, 注意与静态结构sqList的区别,#define List_Init_Len 100 /线性表的初始容量#define Increment 10 /分配增量typedef int DataType /元素类型DataType简化为int型typedef struct DataType *Elem; /数据元素的存放地址(基址)int length; /线性表中的元素个数(实际长度)int ListSize;
15、/线性表容量 SqList;,2.2.2 线性表的顺序动态结构及实现(重点),2018/9/6,25,/*构造一个空的线性表L,成功返回其地址,否则返回0*/ SqList * InitListsq1() SqList *L=(SqList *)malloc(sizeof(SqList); /申请表头空间if (!L) return 0; /*分配失败*/申请线性表数据元素的存储空间L-elem=(DataType*)malloc(List_Init_Len*sizeof(DataType);if (L-elem=0) return 0; /*分配失败*/*存储空间分配成功,为变量L指向的成员
16、赋值*/L-length=0;L-ListSize=List_Init_Len;return (L); /*返回指向线性表结构的指针*/ 注意主程序中的调用方法: SqList *list1 /*声明指针*/ List1=InitListsq1();,2.2.2 线性表的顺序动态结构及实现,2018/9/6,26,/*构造一个空的线性表L,成功返回其地址,否则返回0*/ void InitListsq2(Sqlist *L) /申请线性表数据元素的存储空间L-elem=(DataType*)malloc(List_Init_Len*sizeof(DataType);if (L-elem=0)
17、return 0; /*分配失败*/*存储空间分配成功,为变量L指向的成员赋值*/L-length=0;L-ListSize=List_Init_Len;return (L); /*返回指向线性表结构的指针*/ 注意主程序中的调用方法: SqList list1;InitListsq2 ),2.2.2 线性表的顺序动态结构及实现,2018/9/6,27,/*构造一个空的线性表L,成功返回ok*/ Status InitListsq2(SqList *L) /申请线性表数据元素的存储空间L-elem=(DataType*)malloc(List_Init_Len*sizeof(DataType)
18、;if (L-elem=0) return 0; /*分配失败*/*存储空间分配成功,为变量L指向的成员赋值*/L-length=0;L-ListSize=List_Init_Len;return (ok); 注意调用方法:Sqlist list2; /*声明结构体*/InitListsq2( /*传递结构体的地址*/,算法的C程序实现2,2018/9/6,28,2.2.2 线性表的顺序动态结构_插入算法,算法2.4插入算法C函数: /*功能:将元素e插入到线性表L的第i个位置,成功返回ok,否则返回错误号*/ 注意:其中的符号常量是用#define预先定义的(第一章的约定)Status In
19、sertElem(SqList L,int i,DataType e) DataType *newbase=0,*q,*p; /*定义局部变量*/if (iL.length+1) printf(“Param Error!”) ; /*插入位置非法 */return (error); if (L.length=L.ListSize) /*表已满*/ / 申请增加存储空间newbase=(DataType*)realloc(L.elem,(L.Length+Increment)*sizeof(DataType);if (!newbase) exit(“overflow!”) ; /*存储空间分配失
20、败*/,2018/9/6,29,算法2.4插入算法C函数:/*存储空间分配成功*/L.elem=newbase;L.ListSize+=Increment; q=如果将L定义为指向结构体SqList的指针,则访问成员变量的语法为:指针变量名-成员名 等价于(*指针变量).成员),2018/9/6,30,算法2.4插入算法C函数:/*存储空间分配成功*/L.elem=newbase;L.ListSize+=Increment; q=如果将L定义为指向结构体SqList的指针,则访问成员变量的语法为:指针变量名-成员名,2018/9/6,31,2.2.2 线性表的顺序动态结构_删除算法,静态结构线
21、性表的删除算法,请修改 /删除线性表中第i个位置上的元素,并用变量e 返回 Status Delelem(SqList *L,int i , DataType *e) if (iL-length) /检查空表及删除位置的合法性 printf (“不存在第i个元素”);exit(0);*e=L-elemi-1;for(j=i; jlength-1;j+)L-elemj-1=L-elemj; /向前移动元素L-length-; return ok;,2018/9/6,32,线性表顺序存储结构中任意数据元素的存储地址可由公式直接导出,因此可以 随机存取 其中的任意元素。但是,顺序存储结构也有一些不方便之处,主要表现在: (1)数据元素集最大个数需预先确定(静态结构),使得高级程序设计语言编译系统需预先分配相应的存储空间; (2)插入与删除运算的效率很低。为了保持线性表中的数据元素顺序,在插入操作和删除操作时需移动大量数据。对于插入和删除操作频繁的线性表、将导致系统的运行速度难以提高。,顺序结构小结:,