链表(上)
Posted hardyyao
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了链表(上)相关的知识,希望对你有一定的参考价值。
链表是什么?
来看看维基百科给出的定义:
- 链表(Linked list)是一种常见的基础数据结构,是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存储到下一个节点的指针(Pointer)。
- 由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度,比数组快得多,但是查找一个节点或者访问特定编号的节点则需要O(n)的时间,而顺序表相应的时间复杂度分别是O(logn)和O(1)。
链表和数组在内存中的分布,大概是这样的:
简单点来说,链表和数组一样是一种线性表的数据结构,不同之处在于,定义一个数组需要申请一块连续的存储空间来存储;而链表恰恰相反,他并不需要一块连续的内存空间,而是在每一个节点里存储到下一个节点的指针,通过“指针”将一组零散的内存块串联起来使用。
常见的链表结构有哪些?
- 单链表
- 循环链表
- 双向链表
单链表
单链表是最简单、最常用的链表结构。
每个链表的节点除了存储数据之外,还需要记录链上的下一个结点的地址。如图所示,这个记录下个结点地址的指针叫作后继指针 next。
图中其中有两个结点是比较特殊的,它们分别是第一个结点和最后一个结点。我们习惯性地把第一个结点叫作头结点,把最后一个结点叫作尾结点。其中,头结点用来记录链表的基地址。有了它,我们就可以遍历得到整条链表。而尾结点特殊的地方是:指针不是指向下一个结点,而是指向一个空地址 NULL,表示这是链表上最后一个结点。
循环链表
循环链表是一种特殊的单链表。它跟单链表唯一的区别就在尾结点,循环链表的尾结点指针是指向链表的头结点。如下图所示:
双向链表
双向链表在实际的软件开发中也很常用,其结构如下图所示:
双向链表需要额外的两个空间来存储后继结点和前驱结点的地址。所以,如果存储同样多的数据,双向链表要比单链表占用更多的内存空间。
但双向链表可以支持双向遍历,它可以支持 O(1) 时间复杂度的情况下找到前驱结点,正是这样的特点,也使双向链表在某些情况下的插入、删除等操作都要比单链表简单、高效。
双向循环链表
把循环链表和双向链表结合起来,就是双向循环链表,如下图所示:
链表和数组各种操作时间复杂度对比
数组简单易用,在实现上使用的是连续的内存空间,可以借助 CPU 的缓存机制,预读数组中的数据,所以访问效率更高。而链表在内存中并不是连续存储,所以对 CPU 缓存不友好,没办法有效预读,访问效率较低。
数组的缺点是大小固定,而且需要一块连续的内存空间。相比起来,链表则较为灵活,没有大小限制,天然支持动态扩容。
内容小结
- 链表是一种非连续性的线性表数据结构。
- 和数组相比,链表更适合插入、删除操作频繁的场景。
- 链表查询的时间复杂度较高,不适用于查询操作频繁的场景。
以上是关于链表(上)的主要内容,如果未能解决你的问题,请参考以下文章
Java连载83-单向链表双向链表collections常用方法