线性表是一种最简单,最基本,也是最常用的数据结构。
线性表中的元素是一对一的关系, 也即除了首元素与尾元素外,其他元素都是首尾相接的。当然,这也有例外, 比如循环链表。
先来看一下线性表的结构图
如果对Java数据体系比较清楚,可能会知道,线性表的结构对应Collection接口下的三个子接口的子类:
List, Set, Queue。
线性表根据表示形式,分为顺序表和链表。顺序表,顾名思义,就是有序存储所有元素的表;而链表,则通过链接的形式来存储。
顺序表
链表
顺序表最典型的例子就是线性数组ArrayList,Array和List的存储形式都是有序按位存储。链表分为单链表与双链表,上图是单链表。我故意将元素不画在一个维度上, 是借此说明一下两者的区别:
1) 数组是按位有序存储, 链表是通过链进行存储
怎么表现呢? 看元素之间的关联。 数组两个元素的关联是通过下标,如array[0]与array[1]; 链表是通过链,如Node1的next是Node2, 这个next就是链,意指下一个元素。
2)数组的空间是连续的, 链表的空间是断续的
数组因为是按位有序存储的,保证元素1与元素2, 元素3...的顺序,因此它的空间必须是连续的; 而链表通过链的指向来建立元素之间的关联,因此不需要连续的空间。
线性表的概念
线性表的长度
线性表中的元素个数,统称为线性表的长度。N个元素的线性表,长度为N; N = 0的线性表称为空表。
线性表的位序
在非空表中每个数据元素都有一个确定的位置,如用ai表示数据元素,则i称为数据元素ai在线性表中的位序。如数组的下标
前驱与后继
线性表的关系是一对一,这就意味着一个元素最多只有一个前驱与后继;在数组A中,假如有A[0]=1, A[1]=2, A[2] =3;那么A[0]就是A[1]的前驱, A[1]则是A[0]的后继。 在链表中,如果有A指向B,B指向C,则A是B的前驱,B是A的后继,以此类推。
线性表的特点
1.集合中必存在唯一的一个“第一元素”与“最后元素”。
3.除最后一个元素之外,均有 唯一的后继。
4.除第一个元素之外,均有 唯一的前驱。
举个例子, 在非空数组,是一定符合上述特征的,因为每个位置存储一个元素,每个元素都是唯一的;一个数组只有一个A[0], 也只有一个A[A.length - 1],A[2]的前驱只有A[1],因为是顺序存储的。在链表中,是如下情况
A->B->C->D
也符合只有一个表头与表尾, 而且每个元素的前驱与后继是唯一的。
本来想着把线性表源码讲解与概念篇放在同一篇文章中,后来想想还是算了;数据结构系列中每一部分都是单讲,因此篇幅比较短,也很好理解;只有到树或图的时候可能篇幅比较长一些。
本篇的主要用意就是让大家熟悉下线性表的基本概念,如什么是长度? 什么是前驱?什么是后继?线性表主要有哪几种?什么是线性表?
上文的概念其实很大部分引用自百度百科, 那么下面通俗的解释一下这些基本概念。
说到线性, 官方的解释就是1对1的关系;已经理解的人对‘线性’二字可能没什么,不了解的人对线性真的可能有点懵。那么什么是线性?什么是1对1关系呢?打个通俗的比方, 你可以把线性表理解为一根绳子,上面打了若干个节,如下图所示
以上图为例解释一下线性表中的概念
这是一根绳子, 上面有4个节。每个节可以称为一个[元素], 那么这跟绳子自然可以看作是一个存储了4个元素的线性表了,也可以说这个线性表的长度是4。 如果把4个节的[位置]分别编号为0, 1,2,3, 把4个节的每个节分别存储一个数字0, 10, 20, 30,把这条绳子记录为一个数组或线性表rope,可以用计算机语言描述为
int[] rope = new int[4]; // rope是一根绳子(比作一个线性表), 绳子上有4个节(表中有4个元素,表的长度是4)
rope[0] = 0; // 第一个节的位置记为0, 数据是0
rope[1] = 10; // 第二个节的位置记为1, 数据是10
rope[2] = 20; // 第三个节的位置记为2, 数据是20
rope[3] = 30; // 第四个节的位置记为3, 数据是30
线性表是一种结构, 它的元素之间保持线性关系,那么什么是线性关系? 线可以理解为一条线, 包含直线和曲线, 直线理解为顺序表, 曲线理解为链表。为什么这么理解呢?
- 上面说过,线性表可以看成一条线。
那么线的构成是先描N个点(元素),然后把点依次连接起来,就成了一条线(两个点的关系,也是两个元素的关系)。
-
顺序表的关系是按顺序规定的, 而链表的关系是通过链。
顺序表的元素之间是靠位置限定的,如数组,List等,为了保证能正常的找到所有元素,每个元素给定一个位置,如第一个节的位置是0, 第二个节的位置是1等。位置也即数组的下标便是两个元素的关系,如在数组中给你两个点rope[0]和rope[1],你就知道这两个点是相邻的。因此在顺序表中,位置即关系。
链表的元素没有位置, 而是通过链指向下一个元素,也即链式关系。上图是个顺序表,那么拿上图举个例子, 现在只有4个节了,任意两个节之间的绳子断了,我们怎么把这四个节串起来呢? 如果上图的四个节分别命名为A,B,C,D; 那么我们可以通过这种方式
第一个节A写上我下一个节是B
第二个节B写上我下一个节是C
...
依次类推,直到最后一个节写上我下一个节是空的,到我就是最后一个了。
这种通过链式关联的数据结构,就是链表,它是线性表的一部分。因为它也是一条线, 一条曲线;什么是曲线? 因为它不需要位置和顺序,知道点A就能知道下一个点B,直到最后一个点N。为什么说它也是线性表?
因为它也是一条线,而不是多条啊。线性关系,说白了就是一条线就能表示出来的关系。
从上述我们了解了顺序表和链表。那么我们分析一下到底谁性能更好呢?我这个性能指的是存储空间的性能,而非使用的性能;使用的性能会在分析完两种数据结构后进行对比。
顺序表因为是顺序的, 所以它需要占用一段连续的空间。就像数组的位置肯定是0, 1, 2,3.. N的,中间不能断开,那样就没有顺序了。
链表是链式的,无论下一个元素在什么位置,上一个元素都会指向它,从而能找到它。因此它的空间不是连续的。
那么结果很明显了, 链表的空间利用率是很高的。因为在我们日常使用中, 会自然的产生一些零碎的,断续的空间。
- 说说前驱和后继
前和后都是相对的位置,一个元素是不分前后的,不是么? 在顺序表中, A的位置是i, B的位置是i+1; 或者在链表中A的next指向B; 其实我们就知道了,B在A的后面,当然A也在B的前面。 那么我们就可以说,A是B的前驱, B是A的后继。
4.再看线性表的特点
说了多次,线性表是一条线。那么这条线肯定只有两个端点, 如果一个是头,那么另一个自然是尾;这就是第一个特点,仅有唯一的头(第一元素)和尾(最后元素)。因为是一条线, 如上图,每个元素的前驱和后继最多只有一个;如果有多于一个的前驱或后继,那么就不是一条线了。
以上篇幅,其实对学过这些的没必要;对没学过的可以加深理解,知道线性表的分类以及概念。关于线性表,你明白了吗?