线性表的定义和基本运算
- 线性表的逻辑定义
(1) 线性表,Linear_List是最简单和最常用的一种数据结构。
(2) 线性表是由n个数据元素(结点)a1,a2,...,an组成的有限序列。类比数学中的数列概念。其中我们规定数组元素的个数n为该线性表的长度,size。当n为零时,称为空表。
(3) 非空的线性表通常记为:(a1,a2,a3,...,an),其中ai(1<=i<=n)表示线性表的其中一个结点。
(4) a1称为表的开始结点,无直接前驱,有一个直接后继a2; an为表的终端结点,无直接后继,有一个直接前驱an-1; 其余元素ai(2<=i<=n-1)为内部元素,有前驱ai-1,后继ai+1;
结点与结点之间是线性的关系。故称之为线性表。
- 线性表的基本运算
(1) 置空表initlist(L),构造一个空的线性表;
(2) 求表长listLength(L),返回线性表的长度;
(3) 取元素getNode(L,i),1<=i<=n;
(4) 按值查找 LocateNode(L,x),返回第一个为X的结点的位置,若表中不存在则返回0
(5) 插入insert(L,i,x) 在L的i位置插入x,
(6) 删除delete(L,i) 删除表中的第i个元素
线性表的顺序存储和基本元素的实现
- 线性表的顺序存储
(1) 线性表的顺序存储指的是将线性表的数据元素按其逻辑顺序依次存入一组地址连续的存储单元中,用这种方式存储的线性表称为顺序表,例如数组。
(2) 假设每个结点的空间大小都一致,即数据类型一致,例如对于每个int来说,占用4个字节,32位。设每个结点的空间大小为d,那么,一般来说,线性表中第i个元素的存储位置为:LOC(ai)=LOC(a1)+(i-1)*d (种树比喻),其中ai的地址称为首地址或基地址。
(3) 因为在顺序表中任何一个元素的地址都可以通过计算确定,所以可以做到随机存储。举例内存的读取模式。
(4) 因为在高级程序设计语言中,数组类型具有随机存取的特性,因此,通常用数组描述顺序表。除了存储线性表的结点外,还需要一个变量(size)来标识线性表的长度。
- 顺序表上基本运算的实现
(1) 随机读取第i个元素,L[i]
(2) 置空表,L.size=0
(3) 插入insert(L,i,x) 在L的i位置插入x
(4) 删除delete(L,i) 删除表中的第i个元素
(5) 倒置列表reverse(L)
线性表的链式存储结构
- 顺序表的读取快,但是插入与删除缓慢,鉴于此,引申出链表
- 链表不可以随机读取,因为第i个元素的地址不能直接读取到
- 单链表(线性链表)
(1) 存储ai时,除了保存ai本身,还存储了ai+1的地址信息,即C中的指针。包含了两部分信息的结点,含有原有数据的域为数据域,存储直接后继的为指针域。
(2) 采取这种存储方式的表为链表,其中每一个结点的存储结构为:[data][next]
(3) 因为每一个结点只包含1个指针域,所以称为单链表。
(4) 因为第一个结点没有直接前趋,所以特地设立一个head存放第一个元素的地址,即头指针。而终端结点的指针域则为null。如果表中一个结点也没有,则head=NULL
- 单链表上的运算
(1) 建立单链表:
① 头插法:(符合先进后出特点,是天生的链栈)
从一个空表开始,重复读入数据,生称新结点,将数据存到数据域中,然后将新结点的地址存到表头上。 插入顺序与链表顺序相反。
头插法步骤:(如图黑线所示,即为链栈的插入结果)
(1)判断插入列表是否为空。即长度size?=0;
(2)读取当前head值。已知头指针head的当前值为null;head.next = null,元素data的自身地址为stu0,stu0. next = null;
(3)令头指针的值指向新元素的地址。即head.next = stu0;
当下一个元素进行插入时,循环上述步骤;即当size = 1时;head.next = stu0,stu1只识别头指针,将stu1.next = head.next,即stu1.next = stu0;最后再将head.next = stu1。
② 尾插法:(符合先进先出的特点,是天生的链队列)
将新结点插入到当前链表的表尾,需要一个尾部指针,rear,使其始终指向链表的尾结点。
尾插法步骤:(如图红线所示,即为链表的插入过程)
(1)与头插法相同,先判断表长size ?= 0;
(2)读取当前rear值。当size = 0时,读取当前rear值为null;
(3)令尾指针rear指向新元素地址。head.next = stu1; rear.next = stu1.next 。
需注意头指针head指向头元素后将不再变化,即head.next = stu1保持不变;尾插法只移动尾指针rear。
当下一个元素进行插入时,循环上述步骤;即当size = 1时; rear.next = stu1.next;stu2只识别尾指针rear,将rear.next = stu2,即stu1.next = stu2;
最后再将rear.next =stu2.next。
(2) 查找运算:
① 因为链表中的地址隐含在前趋中,所以必须从head开始查找
② 按结点序号查找
③ 按结点值查找
(3) 插入运算
(4) 删除运算
- 单循环列表:终端元素设置为a1的地址,可以从任意一个位置开始查找。
- 双向链表:在指针域中加入前趋的地址,可以双向查找。
- 结合以上的特点可以形成循环双向链表。