定义
数组和链表都属于“线性表”,也就是数据排列成一条线一样的结构,线性表,只有前后两个方向。
数组
数组(Array)是一种线性表数据结构。它用一组连续的内存空间,来存储一组具有相同类型的数据。
因为需要连续的内存空间,所以即使内存中宗空间足够大,但是只要不是连续的,数组就不能成功申请到内存。也就是说只要知道数组中第一个对象的位置,我们可以很轻易的通过偏移量来定位数组中其他数据的位置。
链表
链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针连接次序实现的。
链表比数组复杂一点,常用的链表有单链表,双向链表和循环链表,链表中的数据,通过指针来串联,就单链表来说,只有当前对象才知道下一个对象的位置在哪儿。也就是说,只有相邻的两个对象之间才有关系,所以我们可以通过改变指针,来轻松的在任何位置添加或者删除数据。
应用
大多数开发语言都会有数组和链表的数据结构提供使用,以下以java为例。
数组
java语言中,既直接提供了数组,比如int[],也提供了数组的封装,比如ArrayList,对于我来说,我常用的其实是容器ArrayList,因为它封装了数组的添加,插入,删除时的细节,而且还支持动态扩容。
如果想要表示基本类型的数组,那我们只能选择数组,还有就是多维数组,其实使用数组表示更好一些,比如int[][]来表示二维数组。
Vector底层是数组。Stack底层是Vector,所以也可以看作是数组。
链表
java语言中,链表就是LinkedList,LinkedList是双向链表,也就是每个对象不仅知道自己后面是谁,还知道自己前面是谁。
变形
很多其他的数据结构,其实用数组和链表包装一下都可以实现。「队列」、「栈」这两种数据结构既可以使用链表也可以使用数组实现。用数组实现,就要处理扩容缩容的问题;用链表实现,没有这个问题,但需要更多的内存空间存储节点指针。
「图」的两种表示方法,邻接表就是链表,邻接矩阵就是二维数组。邻接矩阵判断连通性迅速,并可以进行矩阵运算解决一些问题,但是如果图比较稀疏的话很耗费空间。邻接表比较节省空间,但是很多操作的效率上肯定比不过邻接矩阵。
「散列表」就是通过散列函数把键映射到一个大数组里。而且对于解决散列冲突的方法,拉链法需要链表特性,操作简单,但需要额外的空间存储指针;线性探查法就需要数组特性,以便连续寻址,不需要指针的存储空间,但操作稍微复杂些。
「树」,用数组实现就是「堆」,因为「堆」是一个完全二叉树,用数组存储不需要节点指针,操作也比较简单;用链表实现就是很常见的那种「树」,因为不一定是完全二叉树,所以不适合用数组存储。为此,在这种链表「树」结构之上,又衍生出各种巧妙的设计,比如二叉搜索树、AVL 树、红黑树、区间树、B 树等等,以应对不同的问题。
了解 Redis 数据库的朋友可能也知道,Redis 提供列表、字符串、集合等等几种常用数据结构,但是对于每种数据结构,底层的存储方式都至少有两种,以便于根据存储数据的实际情况使用合适的存储方式。