![2ddce17831db207665a6181809714a89.png](https://i-blog.csdnimg.cn/blog_migrate/537bcd77efeded2a64c5f03b18ee7831.jpeg)
1、什么是链表
链表,使用“链子”将数据组合起来,这里的链子指的就是引用或者指针。链子存储在哪里呢?节点(Node)中,我们把节点封装在类中。即
class
也就形成了这样的数据结构
![4eb358da11ccafa4e7b4a91dd49ac2ee.png](https://i-blog.csdnimg.cn/blog_migrate/3f7c919acabfe6e6c732a85b3b6b5241.jpeg)
1.1、同数组的区别
上面就是链表,同动态数组不同,链表才算是真正的动态。
动态数组 + 优点:具备随机访问能力,直接根据地址寻址一步完成 + 缺点:不具备真正的动态性,底层依然依靠固定容量的数组
链表 + 优点:具有真正的动态性,完全根据用户的数据建立节点 + 缺点:缺少了随机访问能力,不适合应对查询元素频繁的场景
1.2、节点的实现
由于设计链表类的时候,节点作为链表存储数据的核心。那么节点类就要作为链表类的子类,所以具体的Java实现如下:
public
2、链表的方法实现
几乎所有的数据结构的实现都避免不了增删改查四中基本操作,下面分别实现一下。
写在前面: 为了更优化添加元素或者删除中对头结点的另外操作,这里我引入虚拟头结点(dummyNode)。
2.1、增加元素
增加元素最基本的操作就是向某一个“索引”位置添加元素。
步骤: 1. 找到要插入位置的前一个节点pre 1. 新增节点,并指向pre节点的下一个节点 2. 将pre节点指向新的节点
![ec131884c4eb013dee0ce85f116203ec.png](https://i-blog.csdnimg.cn/blog_migrate/a616cf4cb4f4654c222ca39cd1f2588c.jpeg)
由于我们需要索引到待添加元素的前一个位置,所以我们起始的节点放在虚拟头结点上。这样就可以循环index找到待添加位置的前一个位置。
程序实现
public
2.2、删除元素
步骤: 1. 找到索引位置的前一个节点pre 2. pre节点指向pre节点的下一节点的下一个节点 3. 断开待删除节点与其下一个节点的连接,删除的节点会被内存管理机制自动销毁
![ce158e89f4416c799265100299846e3d.png](https://i-blog.csdnimg.cn/blog_migrate/921992858f47dc6698c72de3924802c9.jpeg)
和添加元素相同,我们需要先找到待删除位置的前一个位置,所以依然以虚拟头节点作为起始节点。
程序实现:
public
写在后面: 在某些场景中,我们并不需要保留这个节点,为了使代码更加简洁易懂我们可以做以下处理。
这种可以应用在LeetCode中,因为在代码执行完成以后,所有都会被销毁。
public
2.3、改变元素
改变元素就比较简单,直接找到位置进行更改元素就可以。同增加元素和删除元素不同,改变元素不需找到前一个位置,所以起始位置就是虚拟头节点的下一个位置。
程序实现:
public
2.4、查询元素
和其他数据结构相同,包含三种查询。 1. find(E e) 查询元素e所在位置 2. contains(E e) 查询是否包含元素,同find代码逻辑相同 3. get(int index) 查询index位置上的元素
/** 是否包含元素 **/
3、时间复杂度分析
对于链表来说,最大的优势在于其动态性,所以在头部进行的所有操作时间复杂度最低O(1)级别,其他位置的操作均与索引位置位置有关(因为要先找到要操作的位置)。由此特性,我们可以清楚的看出,用链表实现栈的数据结构再合适不过啦。
最后
更多精彩内容,大家可以转到我的主页:
首页 | 曲怪曲怪quguaiquguai.cn:8090源码地址:大家可以在上面我的主页中->更多链接里面,谢谢大家的观看收藏。