LinkedList与链表

本文分析了ArrayList的性能缺陷,特别是在插入和删除元素时的时间复杂度,随后介绍了LinkedList,特别是无头双向链表的结构和常见应用场景。文章还探讨了链表的实现,如单向链表的插入、删除操作,以及如何使用快慢指针检测链表环。
摘要由CSDN通过智能技术生成

ArrayList的缺陷

        通过源码知道,ArrayList底层使用数组来存储元由于其底层是一段连续空间,当ArrayList任意位置插入或者删除元素时,就需要将后序元素整体往前或者往后   搬移,时间复杂度为O(n),效率比较低,因此ArrayList不适合做任意位置插入和删除比较多的场景。因此:java 集合中又引入了LinkedList,即链表结构。

链表

链表的概念及结构

        链表是一种物理存储结构上非连续存储结构,数据元素的逻辑顺序是通过链表中的引用链接次序实现的 。

实际中链表的结构非常多样,以下情况组合起来就有8种链表结构:

单向或者双向

 

带头或者不带头

循环或者非循环

 

虽然有这么多的链表的结构,但是重点使用这两种:

        无头单向非循环链表结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结构的子结构,如哈希桶、图的邻接表等等。另外这种结构在笔试面试中出现很多。

        无头双向链表:在Java的集合框架库中LinkedList底层实现就是无头双向循环链表。

链表的实现

// 1、无头单向非循环链表实现
public class SingleLinkedList {
//头插法
public void addFirst(int data);
//尾插法
public void addLast(int data);
//任意位置插入,第一个数据节点为0号下标
public boolean addIndex(int index,int data);
//查找是否包含关键字key是否在单链表当中
public boolean contains(int key);
//删除第一次出现关键字为key的节点
public void remove(int key);
//删除所有值为key的节点
public void removeAllKey(int key);
//得到单链表的长度public int size(); 
public void display(); 
public void clear();
}
  1. 链表面试题
  1. 删除链表中等于给定值 val 的所有节点。 OJ链接
  2. 反转一个单链表。 OJ链接
  1. 给定一个带有头结点 head  的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。OJ链接
  2. 输入一个链表,输出该链表中倒数第k个结点。 OJ链接
  3. 将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。OJ     链接
  4. 编写代码,以给定值x为基准将链表分割成两部分,所有小于x的结点排在大于或等于x的结点之前 。OJ链接
  5. 链表的回文结构。OJ链接
  6. 输入两个链表,找出它们的第一个公共结点。OJ链接
  1. 给定一个链表,判断链表中是否有环。 OJ链接

【思路】

        快慢指针,即慢指针一次走一步,快指针一次走两步,两个指针从链表其实位置开始运行,如果链表  带环则一定会在环中相遇,否则快指针率先走到链表的末尾。比如:陪女朋友到操作跑步减肥。

【扩展问题】

为什么快指针每次走两步,慢指针走一步可以?

        假设链表带环,两个指针最后都会进入环,快指针先进环,慢指针后进环。当慢指针刚进环时,可能就和快  指针相遇了,最差情况下两个指针之间的距离刚好就是环的长度。此时,两个指针每移动一次,之间的距离  就缩小一步,不会出现每次刚好是套圈的情况,因此:在满指针走到一圈之前,快指针肯定是可以追上慢指针的,即相遇。

快指针一次走3步,走4步,...n步行吗?

  1. 给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 NULL OJ链接结论

让一个指针从链表起始位置开始遍历链表,同时让一个指针从判环时相遇点的位置开始绕环运行,两个指针  都是每次均走一步,最终肯定会在入口点的位置相遇


证明

LinkedList的模拟实现

LinkedList底层就是一个双向链表,来实现一个双向链表。

LinkedList的使用

什么是LinkedList

LinkedList 的官方文档

        LinkedList的底层是双向链表结构(链表后面介绍),由于链表没有将元素存储在连续的空间中,元素存储在单独的节   点中,然后通过引用将节点连接起来了,因此在在任意位置插入或者删除元素时,不需要搬移元素,效率比较高。

 

在集合框架中,LinkedList也实现了List接口,具体如下:

【说明】

        LinkedList实现了List接口

        LinkedList的任意位置插入和删除元素时效率比较高,时间复杂度为O(1)

        LinkedList没有实现RandomAccess接口,因此LinkedList不支持随机访问

        LinkedList的底层使用了双向链表

LinkedList的使用

        LinkedList的构造

方法

解释

LinkedList()

无参构造

public LinkedList(Collection<? extends E> c)

使用其他集合容器中元素构造List

LinkedList的其他常用方法介绍

方法

解释

boolean add(E e)

尾插 e

void add(int index, E element)

e 插入到 index 位置

boolean addAll(Collection<? extends E> c)

尾插 c 中的元素

E remove(int index)

删除 index 位置元素

boolean remove(Object o)

删除遇到的第一个 o

E get(int index)

获取下标 index 位置元素

E set(int index, E element)

将下标 index 位置元素设置为 element

void clear()

清空

boolean contains(Object o)

判断 o 是否在线性表中

int indexOf(Object o)

返回第一个 o 所在下标

int lastIndexOf(Object o)

返回最后一个 o 的下标

List<E> subList(int fromIndex, int toIndex)

截取部分 list

LinkedList的遍历

ArrayListLinkedList的区别

不同点

ArrayList

LinkedList

存储空间上

物理上一定连续

逻辑上连续,但物理上不一定连续

随机访问

支持O(1)

不支持:O(N)

头插

需要搬移元素,效率低O(N)

只需修改引用的指向,时间复杂度为O(1)

插入

空间不够时需要扩容

没有容量的概念

应用场景

元素高效存储+频繁访问

任意位置插入和删除频繁

  • 27
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值