线性表(一)
一、线性表的定义
线性表(List):零个或多个数据元素的有限序列
- 第一个元素无前驱,最后一个元素无后继,其他每个元素有且仅有一个前驱和后继
- 线性表强调是有限的
若将线性表记为(a~1~,…,a~i-1~,a~i~,a~i+1~,…,a~n~),则表中a~i-1~领先于a~i~,a~i~领先于a~i+1~,称a~i-1~是a~i~的==直接先驱元素==,a~i+1~是a~i~的==直接后驱元素==。当i=1,2,…,n-1时,a~i~有且仅有一个直接后继,当i=2,3,…,n 时,a~i~有且仅有一个直接前驱
所以线性表元素的个数n(n>=0)定义为==线性表的长度==,当n=0时,称为==空表==。
在非空表中的每个数据元素都有一个确定的位置,如a~1~是第一个 数据元素,a~n~是最后一个数据元素,a~i~是第i个数据元素,称i为数据元素a~i~在线性表中的==位序==
- 在较复杂的线性表中,一个数据元素可以由若干个数据项组成
当你传递一个参数给函数的时候,这个参数会不会在函数内被改动决定了使用什么参数形式
如果需要被改动,则需要传递指向这个参数的指针
如果不用被改动,可以直接传递这个参数
二、线性表的顺序存储结构
1.顺序存储定义
线性表的顺序存储结构,指的是用一段地址连续的存储单元依次存储线性表的数据元素
2.顺序存储方式
可以用一维数组来实现顺序存储结构
3.地址计算方法
- 线性表的第i个元素是要存储在数组下标为i-1的位置,即数据元素的序号和存放它的数组下标至今啊存在对应关系
- 存储器中的每个存储单元都有自己的编号,这个编号称为地址
假设占用的是c个存储单元,那么线性表中第i+1个数据元素的存储位置和第i个数据元素的存储位置满足下列关系(LOC表示获得存储位置的函数)
==LOC(a~i+1~) = LOC(a~i~) + c==
所以对于第i个数据元素a~i~的存储位置可以由a~i~推算得出:
==LOC(a~i~) = LOC(a~1~) + (i - 1) * c==
三、顺序存储结构的插入与删除
1.插入操作
插入算法的思路:
- 如果插入位置不合理,抛出异常
- 如果线性表长度大于等于数组长度,则抛出异常或动态增加容量
- 从最后一个元素开始向前遍历到第i个位置,分别将它们都向后移动一个位置
- 将要插入元素填入位置i处
- 表长加1
2.删除操作
删除算法的思路:
- 如果删除位置不合理,抛出异常
- 取出删除元素
- 从删除元素位置开始遍历到最后一个元素位置,分别将他们都向前移动一个位置
- 表长减1
3.线性表顺序存储结构的优缺点
优点:
- 无须为表示表中元素之间的逻辑关系而增加额外的存储空间
- 可以快速地存取表中任一位置的元素
缺点:
- 插入和删除元素操作需要移动大量元素
- 当线性表长度变化较大时,难以确定存储空间的容量
- 造成存储空间的“碎片”
四、线性表的链式存储结构
1.线性表链式存储结构定义
为了表示每个数据元素a~i~与其直接后继数据元素a~i+1~之间的逻辑关系,对数据元素a~i~来说,除了存储其本身的信息之外,还需存储一个只是其后继的信息(即直接后继的存储位置)我们把存储数据元素信息的域称为==数据域==,把存储直接后继位置的域称为==指针域==。指针域中存储的信息称作==指针==或==链==。这两部分信息组成数据元素a~i~的存储映像,称为==结点==(Node)
- n个结点(a~i~的存储映像)链结成一个链表,几位线性表的链式存储结构,因为此链表的每个结点中只包含一个指针域,所以叫做==单链表==
- 我们把链表中第一个结点的存储位置叫做头指针,整个链表的存取必须从头指针开始进行
- 线性链表的最后一个结点之阵位“空”(通常用NULL或“^”符号表示)
- 有时为了更加方便的对链表进行操作,会在单链表的第一个结点前附设一个结点,称为头结点
2.头指针与头结点的异同
头指针
- 头指针是指链表指向第一个结点的指针,若链表有头结点,则是指向头结点的指针
- 头指针具有标志作用,所以常用头指针冠以链表的名字
- 无论链表是否为空,头指针均不为空。头指针是链表的必要元素
头结点
- 头结点是为了操作的统一和方便而设立的,放在第一元素的结点之前,其数据域一般无意义(也可存放链表的长度)
- 有了头结点,对在第一元素结点前插入结点和删除第一结点,其操作与其他结点的操作就统一了
- 头结点不一定是链表必须要素
五、单链表的读取
获得链表第i个数据的算法思路:
- 声明一个指针p指向链表的第一个结点,初始化j从1开始
- 当j>i时,就遍历链表,让p的指针向后移动,不断指向下一结点,j累加1
- 若到链表末尾p为空,则说明第i个结点不存在
- 否则查找成功,返回结点p的数据
六、单链表的插入和删除
1.单链表的插入
单链表第i个数据插入结点的算法思路:
- 声明一指针p指向链表头结点,初始化j从1开始
- 当j<i时,就遍历链表,让p的指针向后移动,不断指向下一结点,j累加1
- 若到链表末尾p为空,则说明第i个结点不存在
- 否则查找成功,在系统中生成一个空结点s
- 将数据元素e赋值给s->data
- 单链表的插入标准语句s->next = p->next; p->next = s;
- 返回成功
2.单链表的删除
单链表第i个数据删除结点的算法思路:
- 声明一指针p指向链表头结点,初始化j从1开始
- 当j<i时,就遍历链表,让p的指针向后移动,不断指向下一结点,j累加1
- 若到链表末尾p为空,则说明第i个结点不存在
- 否则查找成功,将欲删除的结点p->next赋值给q
- 单链表的删除标准语句 p->next = q->next
- 将q结点中的数据复制给e,作为返回
- 释放q结点
- 返回成功
对于插入或删除数据越频繁的操作,单链表的效率优势就越明显
七、单链表的整表创建
创建单链表的过程就是一个动态生成链表额过程。即从“空表”的初始状态起,依次建立各元素结点,并逐个插入链表
单链表整表创建的算法思路:
- 声明一指针p和计数器变量i
- 初始化一空链表L
- 让L的头结点的指针指向NULL,即建立一个带头结点的单链表
循环
- 生成一新结点复制给p
- 随机生成艺术字赋值给p的数据域p->data
- 将p插入到头结点与前一新结点之间
八、单链表的整表删除
单链表整表删除的算法思路:
- 声明一指针p和q
- 将第一个结点赋值给p
循环:
- 将下一结点赋值给q
- 释放p
- 将q赋值给p
九、单链表结构与顺序存储结构的优缺点
存储分配方式
- 顺序存储结构用一段连续存储单元依次存储线性表的数据元素
- 单链表采用链式存储结构,用一组任意的存储单元存放线性表的元素
时间性能
查找
- 顺序存储结构 O(1)
- 单链表O(n)
插入和删除
- 顺序存储结构需要平均移动表长一般的元素,时间复杂度为O(n)
- 单链表在找出位置的指针后,插入和删除时间复杂度仅为O(1)
空间性能
- 顺序存储结构需要预分配存储空间,分大了,浪费,分小了易发生上溢
- 单链表不需要分配存储空间,只要有就可以分配,元素个数也不受限制
结论
- 若线性表需要频繁查找,很少进行插入和删除操作时宜采用顺序存储结构
- 当线性表中的元素个数变化较大或者根本不知道有多大时,最好用单链表结构