LinkedList源码解析(手把手带你熟悉链表)

//创建一个新节点
NodeBean newNode = new NodeBean();
//为节点赋值
newNode.value = value;
//左节点为最后一个节点(尾节点)
newNode.leftNode = lastNode;
//由于是添加节点,所以右节点为null,可以不写
newNode.rightNode = null;
//将成员变量的最后一个节点改为当前新节点
this.lastNode = newNode;
//判断头节点是否为空
if (this.firstNode == null) {
//如果为空说明当前是第一个节点,需要把头结点也设为当前节点
this.firstNode = newNode;
}else{
//如果不为空,需要把前一个节点的右节点指向当前节点
//两个节点相连接的条件是:
// 1. 前一个节点的右节点指向当前节点
// 2. 当前节点的左节点指向上一个节点
lastNode.rightNode = newNode;
}
//链表长度+1
size++;
}

  • 节点怎么断开?

两个节点断开只需要将自己的上一个节点的右节点指向自己的下一个节点左节点,同时自己的下一个节点的左节点,指向上一个节点的右节点

注意看下图箭头方向,这样节点2就可以直接断开,节点1和节点3直接连接,这里也可以很明显的看出,链表增删很快,只需要断开前后节点就可以

在这里插入图片描述

先看一下断开节点的大概代码思路:

节点2.左节点 = null
节点2.右节点 = null
节点1.右节点 = 节点3
节点3.左节点 = 节点1

这样就可以断开当前节点,并且将链表重新连接起来

现在我们来实现remove(index)方法,根据索引删除指定节点:

/**

  • 删除值
    */
    public void remove(int index){
    这里代码通过索引查找节点,为了简化代码,请忽略这里的代码
    通过索引查找节点,下面会写到

    indexNode就是我们通过索引拿到的节点

indexNode = 通过索引查找节点(index)

//拿到该节点的左节点、右节点以及值
NodeBean leftNode = indexNode.leftNode;
NodeBean rightNode = indexNode.rightNode;

//判断左节点是否为空,如果为空说明当前节点为(头结点)第一个节点
if (leftNode == null) {
this.firstNode = indexNode;
}else{
//左节点不为空,需要断开自己的左节点
indexNode.leftNode = null;
//将上一个节点的右节点连接到下一个节点
leftNode.rightNode = rightNode;
}

//判断右节点是否为空,如果为空说明当前为(尾节点)最后一个节点
if (rightNode == null) {
this.lastNode = indexNode;
}else{
//右节点不为空,需要断开自己的右节点
indexNode.rightNode = null;
//将下一个节点的左节点连接到上一个节点
rightNode.leftNode = leftNode;
}

//当前节点值置空
indexNode.value = null;
size–;
}

  • 通过索引查找节点

  1. 先拿到头节点
  2. 拿到当前要查找的索引index
  3. 循环index的次数
  4. 每循环一次,就从头结点开始往后移动一个节点

现在我们来实现以下get(index)方法,通过索引获取置顶节点:

/**

  • 通过索引获取节点的值
    */
    public String get(int index){
    //由于链表没有索引,所以只能一个一个遍历查找
    //先拿到链表的第一个节点(头节点)
    NodeBean firstNode = this.firstNode;
    for (int i = 0; i < index; i++) {
    //每次循环就从头结点往后挪动一个节点
    firstNode = firstNode.rightNode;
    }
    //为了简化代码便于理解,这里不考虑tempNode为null的情况
    return firstNode.value;
    }

  • 总结

  1. 链表的每个节点之间都有连接,如果新增节点只需要直接插入就行,所以链表新增快
  2. 链表断开节点只需要将自己的前后节点重新连接就可以,所以链表删除快
  3. 链表没有索引,查找需要循环整个链表,所以查询慢
  • MyLinkedList完整代码:

public class MyLinkedList {
private int size; //当前链表的长度
private NodeBean firstNode; //头节点
private NodeBean lastNode; //尾节点

/**

  • 添加值
    */
    public void add(String value) {
    //先获取尾节点
    NodeBean lastNode = this.lastNode;
    //创建一个新节点
    NodeBean newNode = new NodeBean();
    //为节点赋值
    newNode.value = value;
    //左节点为最后一个节点(尾节点)
    newNode.leftNode = lastNode;
    //由于是添加节点,所以右节点为null,可以不写
    newNode.rightNode = null;
    //将成员变量的最后一个节点改为当前新节点
    this.lastNode = newNode;
    //判断头节点是否为空
    if (this.firstNode == null) {
    //如果为空说明当前是第一个节点,需要把头结点也设为当前节点
    this.firstNode = newNode;
    }else{
    //如果不为空,需要把前一个节点的右节点指向当前节点
    //两个节点相连接的条件是:
    // 1. 前一个节点的右节点指向当前节点
    // 2. 当前节点的左节点指向上一个节点
    lastNode.rightNode = newNode;
    }
    //链表长度+1
    size++;
    }

/**

  • 删除值
    */
    public void remove(int index){
    //先找到当前索引对应的节点
    //由于链表没有索引,所以只能一个一个遍历查找
    //先拿到链表的第一个节点(头节点)
    NodeBean indexNode = this.firstNode;
    for (int i = 0; i < index; i++) {
    //每次循环就从头结点往后挪动一个节点
    indexNode = indexNode.rightNode;
    }
    //拿到该节点的左节点、右节点以及值
    NodeBean leftNode = indexNode.leftNode;
    NodeBean rightNode = indexNode.rightNode;

//判断左节点是否为空,如果为空说明当前节点为(头结点)第一个节点
if (leftNode == null) {
this.firstNode = indexNode;
}else{
//左节点不为空,需要断开自己的左节点
indexNode.leftNode = null;
//将上一个节点的右节点连接到下一个节点
leftNode.rightNode = rightNode;
}

//判断右节点是否为空,如果为空说明当前为(尾节点)最后一个节点
if (rightNode == null) {
this.lastNode = indexNode;
}else{
//右节点不为空,需要断开自己的右节点
indexNode.rightNode = null;
//将下一个节点的左节点连接到上一个节点
rightNode.leftNode = leftNode;
}

//当前节点值置空
indexNode.value = null;
size–;
}

/**

  • 通过索引获取节点的值
    */
    public String get(int index){
    //由于链表没有索引,所以只能一个一个遍历查找
    //先拿到链表的第一个节点(头节点)
    NodeBean firstNode = this.firstNode;
    for (int i = 0; i < index; i++) {
    //每次循环就从头结点往后挪动一个节点
    firstNode = firstNode.rightNode;
    }
    //为了简化代码便于理解,这里不考虑tempNode为null的情况
    return firstNode.value;
    }

/**

  • 获取链表长度
    */
    public int getSize(){
    return this.size;

尾声

面试成功其实都是必然发生的事情,因为在此之前我做足了充分的准备工作,不单单是纯粹的刷题,更多的还会去刷一些Android核心架构进阶知识点,比如:JVM、高并发、多线程、缓存、热修复设计、插件化框架解读、组件化框架设计、图片加载框架、网络、设计模式、设计思想与代码质量优化、程序性能优化、开发效率优化、设计模式、负载均衡、算法、数据结构、高级UI晋升、Framework内核解析、Android组件内核等。

不仅有学习文档,视频+笔记提高学习效率,还能稳固你的知识,形成良好的系统的知识体系。这里,笔者分享一份从架构哲学的层面来剖析的视频及资料分享给大家梳理了多年的架构经验,筹备近6个月最新录制的,相信这份视频能给你带来不一样的启发、收获。

Android进阶学习资料库

一共十个专题,包括了Android进阶所有学习资料,Android进阶视频,Flutter,java基础,kotlin,NDK模块,计算机网络,数据结构与算法,微信小程序,面试题解析,framework源码!

image

大厂面试真题

PS:之前因为秋招收集的二十套一二线互联网公司Android面试真题 (含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)

《2017-2021字节跳动Android面试历年真题解析》

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

Jl8-1714507999000)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 27
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值