【数据结构与算法】链表(Linked List)


1. 初识链表

动态数组的缺点:

  • 可能会造成内存空间的大量浪费。

用多少申请多少内存?

  • 链表解决

链表是一种链式存储的线性表,所有元素的内存地址不一定连续。

在这里插入图片描述

如何往列表里添加元素:首先创建一个节点对象,在这个节点内部分配一块存储空间出来,来存储真正的数据。

添加新的元素分配新的存储空间,此时内存地址是随机的。

最后一个元素的下一个node地址为null。

链表里至少两个元素:size和first

first第一个节点里应该有element和next

扫描二维码关注公众号,回复: 12070943 查看本文章

element:存放的元素
next:下一个节点
在这里插入图片描述

2. 链表的继承关系

链表的大部分接口与动态数组是一致的。它两都是线性表。
链表的接口设计

用接口的方法。

二者公共的代码
利用继承,抽象线性表,来封装。

让他们的父类abstractList去实现List接口

父类引用指向子类对象

在这里插入图片描述

3. 虚拟头节点

有时候为了让代码更加精简,统一所有节点的处理逻辑,可以在最前面加上一个虚拟的头节点(不存储数据)。[

4. 均摊时间负责度

什么情况下适合使用均摊复杂度?

  • 经过连续多次复杂度比较低的情况后,出现个别复杂度比较高的情况。

5. 动态数据的缩容

如果内存使用比较紧张,动态数组有比较多的剩余空间,可以考虑缩容操作。

6. 复杂度振荡

如果扩容倍数,缩容时机设计不得当,有可能会导致复杂度振荡。

7. 双向链表

此前所学链表是单向链表
使用双向链表可以提升列表的综合性能

单向列表只能从头开始搜索。
在这里插入图片描述

动态数组、双向链表如何选择?
动态数组:开辟、销毁内控空间的次数相对较少,但可能造成内存空间浪费(可以通过缩容解决)。

双向链表:开辟、销毁内控空间的次数相对较多,但不会造成内存空间浪费]\

  • 如果频繁在尾部进行添加、删除操作,动态数组,双向链表都可以选择。
  • 如果如果频繁在头部进行添加、删除操作,建议选择双向链表。
  • 如果有频繁的(在任意位置)进行添加、删除操作,建议使用双向链表
  • 如果有频繁的查询操作(随机访问操作),建议使用动态数组。

有了双向链表,单项链表是否没有用处了?
哈希表的设计中用到了单链表

JAVA的 gc root对象

JAVA的 gc root对象,如果对象不是被gc对象引用着,就会回收内存。

  1. 被栈指针(局部变量)指向的对象,栈:局部变量
    举例:List list = new ArrayList<>();
    list是栈里面的指针,new出来的ArrayList是在堆空间中,所以new ArrayList这个对象就可以称之为 gc root 对象。

判断是否被回收:finalize()

8. 单向循环链表

在这里插入图片描述
在这里插入图片描述

10. 双向循环链表

在这里插入图片描述

add()、 remove() 考虑情况

add():

  1. 往最后一个位置插入元素的情况,原来链表只有一个节点的情况
  2. 其他位置的话,往第一个节点位置插入的情况。

remove():

  1. 只有一个节点的情况,size == 0
  2. 多个节点的话,删除第一个节点和最后一个节点的情况

11. 约瑟夫问题

在这里插入图片描述

发挥循环链表的最大威力

可以考虑增设一个成员变量、3个方法
current : 指向某个节点

void reset() : 让current指向头节点 first

E next() : 让current 往后走一步,即current = current.next

E remove() : 删除current指向的节点,删除成功后让current指向下一个节点。

12. 静态链表

前面所学链表都是依赖指针(引用)实现的。

可以通过数组来模拟链表,称为静态链表。

数组的每个元素存放2个数据: 值、下个元素的索引

数组0位置存放的是头节点的信息。
在这里插入图片描述

结果:11 -> 44 -> 22 -> 55 -> 33

如果数组的每个元素只能存放一个数据?
那就使用2个数组,1个存放索引关系,1个存放值。

猜你喜欢

转载自blog.csdn.net/Cirtus/article/details/109293369
今日推荐