1.1 线性表
1.1.1 线性表的定义
线性表:零个或多个数据元素的有限序列。
线性表,简单的理解,是具有像线一样性质的表。比如放学的小朋友一个跟着一个排成一队,这样如同有一根线把他们串联起来,这样的数据结构,就可以称之为线性表。
1.1.2 顺序存储定义
线性表的顺序存储结构,指的是用一段地址连续的存储单元依次存储线性表的数据元素。
1.1.3 顺序存储方式
线性表的顺序存储结构,说白了,就是在内存中找了块地方,通过占位的形式,把一定内存空间给占了,然后把相同数据类型的数据元素依次存放在这块空地中。既然线性表的每个数据元素的类型都相同,所以可以用 一维数组来实现顺序存储结构,即把第一个数据元素存到数组下标为0的位置中,接着把线性表相邻的元素存储在数组中相邻的位置。
1.1.4 数据长度与线性表长度区别
数组的长度是存放线性表的存储空间的长度,存储分配后这个量一般是不变的。
线性表的长度是线性表中数据元素的个数,随着线性表插入和删除操作的进行,这个量是变化的。
在任意时刻,线性表的长度应该小于等于数组的长度。
1.1.5 地址计算方法
数组下标从0开始,于是线性表的第 i 个元素是要存储在数组下标为 i-1 的位置,即数据元素的序号和存放它的数组下标之间存在对应关系。
用数组存储顺序表意味着要分配固定长度的数组空间,由于线性表中可以进行插入和删除操作,因此分配的数组空间要大于等于当前线性表的长度。
内存中的地址,就和图书馆或电影院里的座位一样,都是有编号的。 存储器中的每个存储单元都有自己的编号,这个编号称为地址。 假设占用的是 c 个存储单元,那么线性表中第 i+1 个数据元素和存储位置和第 i 个数据元素的存储位置满足下列关系(LOC 表示获得存储位置的函数)。
通过这个公式,你可以随时算出线性表中任意位置的地址,不管它是第一个还是最后一个,都是相同的时间。那么我们对每个线性表位置的存入或者取出数据,对于计算机来说都是相等的时间,也就是一个常数,因此用我们算法中学到的时间复杂度的概念来说,它的存取时间性能为O(1)。我们通常把具有这一特点的存储结构称为随机存取结构。
1.1.6 线性表顺序存储结构的优缺点
优点:
- 无须为表示表中元素之间的逻辑关系而增加额外的存储空间。
- 可以快速地存取表中任一位置的元素。
缺点:
- 插入和删除操作需要移动大量元素。
- 当线性表长度变化较大时,难以确定存储空间的容量。
- 造成存储空间的"碎片"。
1.1.7 线性表链式存储结构定义
线性表的链式存储结构的特点是用一组任意的存储单元存储线性表的数据元素,这组存储单元可以是连续的,也可以是不连续的。这就意味着,这些数据元素可以存在内存未被占用的任意位置。
以前在顺序结构中,每个数据元素只需要存数据元素信息就可以了。现在链式结构中,除了要存数据元素信息外,还要存储它的后继元素的存储地址。
因此,为了表示每个数据元素 ai 与其直接后继数据元素 ai+1 之间的逻辑关系,对于数据元素 ai 来说,除了存储其本身的信息之外,还需存储一个指示其直接后继信息(即直接后继的存储位置)。 我们把存储数据元素信息的域称为数据域,把存储直接后继位置的域称为指针域。指针域中存储的信息称做指针或链。这两部分信息组成数据元素 ai 的存储映像,称为结点(Node)
对于线性表来说,总得有个头有个尾,链表也不例外。我们把 链表中第一个结点的存储位置叫做头指针,那么整个链表的存取就必须是从头指针开始进行了。之后的每一个结点,其实就是上一个的后继指针指向的位置。想象一下,最后一个结点,它的指针指向哪里?
最后一个,当然就意味着直接后继不存在了,所以规定线性链表的最后一个结点指针为"空"(通常用NULL或"^"符号表示)
有时,我们为了更加方便地对链表进行操作,会在单链表的第一个结点前附设一个结点,称为头结点。头结点的数据域可以不存储任何信息,有这个特权。也可以存储如线性表的长度等附加信息,头结点的指针域存储指向第一个结点的指针。
1.1.8 头指针和头结点的异同
头指针:
- 头指针是指链表指向第一个结点的指针,若链表有头结点,则是指向头结点的指针。
- 头指针具有标识作用,所以常用头指针冠以链表的名字。
- 无论链表是否为空,头指针均不为空。头指针是链表的必要元素。
头结点:
-
头结点是为了操作的统一和方便而设立的,放在第一元素的结点之前,其数据域一般无意义。(也可存放链表的长度)
-
有了头结点,对在第一元素结点前插入结点和删除第一结点,其操作与其它结点的操作就统一了。
-
头结点不一定是链表必须要素。