二、线性表
2.1、线性表的定义和特点
- 线性表的定义:由n(n≥0)个数据特性相同的元素(结点)a1、a2、····an构成的有限序列称为线性表。
注:将非空的线性表(n>O)记作(a1,a2,a3,...,an)
- 线性表的例子: 26个英文字母的字母表:(A, B, C, ...,Z);学生信息表;12星座。
注: 同一线性表中的元素必定具有相同的特性,数据元素之间关系是线性的。
- 线性表的特点:
- 在非空的线性表,有且仅有一个开始结点a1,它没有直接前趋,而仅有一个直接后继a2。
-
有且仅有一个终端结点an,它没有直接后继,而仅有一个直接前趋an-1。
-
其余的内部结点ai,(2<i<n-1)都有且仅有一个直接前趋ai-1和一个直接后继ai+1。
2.2、线性表的类型定义
- 抽象数据类型线性表的定义如下:
- 基本操作:
- InitList(&L):操作结果:构造一个空的线性表L。
- DestroyList(&L):初始条件:线性表L已经存在;操作结果:销毁线性表L。
- ClearList(&L):初始条件:线性表已经存在;操作结果:将线性表L重置为空表。
- ListEmpty(L):初始条件:线性表L已经存在;操作结果:若线性表L为空表,则返回ture,否则为false。
- ListLength(L):初始条件:线性表L已经存在;操作结果:返回线性表L中的数据元素个数。
- GetElem(L,i,&e):初始条件:线性表L已经存在,1<=i<=ListLength(L)。操作结果:用e返回线性表L中第i个数据元素的值。
- LocateElem(L,e,compare()):初始条件:线性表L已经存在,compare()是数据元素判定函数。操作结果:返回L中第一个与e满足compare()的数据元素的位序。若这样的数据元素不存在则返回值为0。
- PriorElem(L,cur_e,&pre_e):初始条件:线性表L已经存在。操作结果:若cur_e是L的数据元素,且不是第一个,则用pre_e返回它的前驱,否则操作失败;pre_e无意义。
- NextElem(L,cur_e,&next_e):初始条件:线性表已经存在。操作结果:若cur_e是L的数据元素,且不是最后一个,则用next_e返回它的后继,否则操作失败,next_e无意义。
- ListInsert(&L,i,e):初始条件:线性表L已经存在,1<=i<=ListLength(L)+1。操作结果:在L的第i个位置之前插入新的数据元素e,L的长度加1.
- ListDelete(&L,i,&e):初始条件:线性表L已经存在,1<=i<=ListLength(L)。操作结果:删除L的第i个数据元素,并用e返回其值,L的长度减1。
- ListTraverse(&L,visited()):初始条件:线性表L已经存在。操作结果:依次对线性表中的每个元素调用visited()。
注:以上所提及的运算是逻辑结构上定义的运算。只要给出这些运算的功能是“做什么”,至于“如何做”等实现细节,只有待确定了存储结构之后才考虑。
2.3、线性表的顺序表示和实现
- 线性表的存储结构: 在计算机中线性表有两种存储结构分别是顺序存储结构和链式存储结构
2.4.1、线性表的顺序存储表示
-
线性表的顺序表示又称顺序存储结构或顺序映象。
-
顺序存储定义:把逻辑上相邻的数据元素存储在物理上相邻的存储单元中的存储结构。线性表的顺序存储结构是指用一段地址连续的存储单元依次存储线性表的数据元素。
- 顺序表中元素存储位置的计算:
2.4.2、数组长度与线性表长度
- 顺序表中的元素要求地址连续、依次存放、随机存取、类型相同,高级程序设计语言当中可以用一维数组来实现。
- 数组长度:线性表最多可容纳数据元素的个数。
- 线性表长度:当前数据元素的个数。
- 例如:一个教室最多容纳50人(数组长度/线性表的最大存储容量),但现在教室里坐着34(线性表中当前元素个数)个数。
- 一维数组的定义方式:类型说明符 数组名 [常量表达式]。
说明:常量表达式中可以包含常量和符号常量(宏命名),不能包含变量。即C语言中不允许对数组的大小作动态定义。
- 线性表经常进行插入和删除的操作长度可变而C中数组的长度是不可变的。
- 用一个额外的变量表示线性表的长度:
注:ElemType是根据实际问题,你需要什么类型的数组就定义成什么,一般是根据问题定义一个结构体或者是 typedef char ElemType。
2.4.3、类C语言有关操作的补充
- 数组的定义:
- C语言的内存动态分配:
数组名其实就是首元素的地址所以也可以直接定义一个指针。数组的大小用相应的函数来动态分配内存。
- malloc(m)函数 :开辟m字节长度的地址空间,并返回这段空间的首地址。注意要强制类型转换。
- sizeof(x):计算变量/数据类型x所占据的字节数。
- free(p):释放指针p所指变量的存储空间,即彻底删除一个变量。
- 需要加载头文件<stdlib.h>。
- C++的动态存储分配 :
- 传值方式:
- 指针变量作参数:
- 数组名作参数:注意:传递的是数组的首地址;对形参数组所做的任何改变都将反映到实参数组中。
- 引用类型作参数:引用:它用来给一个对象提供一个替代的名字。
注意:引用类型做形参的三点说明:
2.4.4、顺序表的基本操作的实现
- 操作中常用的预定义常量与类型:
- 初始化:
- 销毁线性表:
- 清空线性表:
- 求表长:
- 判断线性表是否为空:
- 查找算法:
- 在线性表L中查找与指定值e相同的数据元素的位置。
- 从表的一端开始,逐个进行记录的关键字和给定值的比较。找到,返回该元素的位置序号,未找到,则返回0。
- 查找算法分析:
- 查找算法的基本操作:将记录的关键字同给定值进行比较(L.elem==e)
比较的次数与输入的定值e有关(假设7个数字出现的概率均为1/7) ,当e=a,1次;当e=b,2次;当e=c,3次;...e=g,7次,平均比较次数(1+2+3+...+7)/7=4。
2.平均查找长度(ASL):在查找时,为确定元素在顺序表中的位置,需和给定值进行比较的数据元素个数的期望值称为查找算法在查找成功时的平均查找长度。
- 插入算法:
- 在线性表a3位置之前插入一个新元素e(e=6) 。
注意:1. 插入位置在最后在线性表的最后添加一个元素不需要移动直接添加
2. 插入位置在最前在原线性表的第1个元素之前插入一个新的元素,线性表的所有元素都要移动,移动次数最多。
3.插入位置中间如上例 :
- 插入算法的算法分析:
- 算法时间主要耗费在移动元素的操作上。
- 若插入到尾节点之后,则无需移动。
- 若插入到首节点之前,则表中所有元素全部后移。
-
- 删除算法:
- 判断删除位置i是否合法(合法值为1≤i≤n)。
- 将欲删除的元素保留在e当中。
- 将第i+l个至第n个的元素依次向前移动一个位置(i= n时无需移动)。
- 表长减1。
- 删除算法的分析:
2.5、小结
- 顺序表的操作算法分析:
- 时间复杂度:查找、插入、删除算法的平均时间复杂度为O(n)。
- 空间复杂度:顺序表操作算法的空间复杂度S(n)=O(1)。(显然没有占用辅助空间) 。
- 顺序表的优缺点:
- 优点:1.存储密度大(结点本身所占用的空间/结点结构所占存储量=1)无需为表示表中元素之间的逻辑关系,而增加额外的存储空间。2.可以随机存取表中任意位置的元素。
- 缺点:1.插入、删除某一元素需移动大量元素。2.当线性表长度变化较大时,难以确定存储空间的容量,数据元素的个数不能自由扩充(存储空间不灵活)
shuzushu'zu