数组
在计算机科学中,数组是我们最熟悉也是最基础的一种数据结构。通常地,数组由有限个相同数据类型的元素按顺序排列组合而成。数组的数据是连续的,并且会设定上界和下界,其中的每个元素都有属于它们自己的索引值(也就是下标),通过这些下标就能定位到元素。对于绝大多数编程语言来说,数组的索引都是从0开始,但不排除有的编程语言从1开始。
几乎所有程序都会使用数组结构,而且很多其他的数据结构也可以由数组来实现,比如栈、队列、列表等。
根据维度不同,数组可以分为一维数组、二维数组、三维数组等,以此类推。
一维数组
在各种维度的数组中,一维数组是最简单的数组结构,通常它也被称为线性数组。
二维数组
由于数学领域中的矩阵可以通过二维数组来表示,因此二维数组也被称为矩阵。此外,因为它是二维的结构,所以需要两个下标才能确定一个元素,即行下标和列下标。
链表
链表是一种线性的数据集合。在链表中,每个节点都指向后继或前驱节点。也就是说每个节点都会包含数据和指针。链表中的节点在逻辑上是相连的,但在物理内存中却是不相连的,这种特性让链表拥有了高效的插入和删除操作。
总的来说,虽然链表实现的存储结构与传统数组的结构类似,但它也有一定的优势。其优势主要体现在两方面:其一,链表能够实现更高效的插入和删除操作。其二,较于数组,它能避免重新分配内存的情况,因为数组是有固定大小的,当数组内存不够使用时,则需要重新分配更大的内存。以上优势得益于链表存储可以是非连续的内存空间,这样就允许在链表的任意位置进行插入和删除操作,并且能在常数的时间复杂度内完成。
当然,链表也有自己的缺点,具体如下:
- 比起数组,链表会占用更多内存空间,因为链表里面需要保存额外的指针。
- 链表不支持随机访问,只能按照顺序从头开始查找,访问时间是线性的,而数组则可以实现随机访问。
- 链表存储的内存是非连续的,在计算机中,这种情况有可能导致访问的效率降低,因为CPU存在缓存机制,而CPU缓存一般是将整块连续内存缓存起来,链表的非连续内存形式会降低CPU缓存的命中率。
- 链表实现逆向遍历比较困难,因为单向链表只能有一个方向的指针,而双向链表虽然多了一个方向的指针,但它会耗费更多的内存。
比较常见的两类链表为单向链表和双向链表。
单向链表
单向链表属于链表的一种,也叫单链表。单向是说它的链接方向是单向的,它由若干个节点组成,每个节点都包含了数据和后继节点指针next,单向链表主要的操作包括插入、删除和遍历。需要注意的是,头部节点head不保存任何数据(也可保存数据,但为了减少一些判断,这里不保存数据),只用于指向单向链表的第一个节点,并且整个链表的指针都指向一个方向。
单向链表的特点
- 创建单向链表时无需指定链表的长度,这比数组更加有优势,而数组纵使定义成动态数组也是需要指定一个更大的数组长度,并且要把原来的数组元素都复制到数组中。
- 单向链表中的节点删除操作很方便,它可以直接通过改变指针指向来实现删除操作,而某些场景下数组的删除操作需要移动剩下的元素。
- 单向链表中的节点需要通过顺序访问,即通过遍历的方式来访问节点,而数组则可以实现随机访问。
树
树是一种很常见的数据结构,它被用来模拟具有树状结构性质的数据集合,由n(n >= 0)个有限节点组成一个具有层次关系的集合。
树的每个节点都有零个或多个子节点;没有父节点的节点被称为根节点;每个非根节点都只有一个父节点;每层子节点所对应的子树都不相交。
节点深度:对于任意节点,该节点的深度为从根节点到该节点的唯一路径长,其中根节点的深度为0,。
节点高度:对于任意节点,该节点的高度为从该节点到该节点子树下各叶子节点的最长路径长,所有叶子节点的高度为0。