Java最新【JDK源码】LinkedList源码分析,java面试题汇总及答案

写在最后

为了这次面试,也收集了很多的面试题!

以下是部分面试题截图

Java程序员秋招三面蚂蚁金服,我总结了所有面试题,也不过如此

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

指定位置添加

//在指定index位置处添加元素

public void add(int index, E element) {

//检查是否越界

checkPositionIndex(index);

//如果index是在队列尾节点之后的一个位置

//把新节点直接添加到尾节点之后

//否则调用linkBefore()方法在中间添加节点

if (index == size)

linkLast(element);

else

linkBefore(element, node(index));

}

//寻找index位置对应的节点

Node node(int index) {

//因为是双链表,所以根据index是在前半段还是后半段决定从前遍历还是从后遍历

//这样index可以少遍历一半的元素

if (index < (size >> 1)) {

//如果是在前半段

//从前遍历

Node x = first;

for (int i = 0; i < index; i++)

x = x.next;

return x;

} else {

//如果是在后半段

//就从后遍历

Node x = last;

for (int i = size - 1; i > index; i–)

x = x.prev;

return x;

}

}

// 在节点succ之前添加元素

void linkBefore(E e, Node succ) {

// 找到待添加节点的前置节点,也就是succ的前置节点

final Node pred = succ.prev;

// 在其前置节点和后继节点之间创建一个新节点

final Node newNode = new Node<>(pred, e, succ);

// 修改后继节点的前置指针指向新节点

succ.prev = newNode;

// 判断前置节点是否为空

//如果为空,说明是第一个添加的元素,修改first指针

//复制修改前置节点的nxet为新节点

if (pred == null)

first = newNode;

else

pred.next = newNode;

//元素个数+1

size++;

//修改次数+1

modCount++;

}

LinkedList在中间添加元素的方法也很简单,典型的双链表在中间添加元素的方法。

总结

添加元素的三种方式大致如下图所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P1Rs1v7r-1641043621838)(LinkedList源码分析.assets/image-20220101211415977.png)]

  • 在队列首尾添加元素很高效,时间复杂度为O(1)。

  • 在中间添加元素比较低效,首先要先找到插入位置的节点,再修改前后节点的指针,时间复杂度为O(n)。

6.删除元素


作为双端队列,删除元素也有两种方式,一种是队列首删除元素,一种是队列尾删除元素。

作为List,又要支持中间删除元素,所以删除元素一个有三个方法,分别如下:

删除头节点

//remove的时候如果没有元素抛出异常

public E removeFirst() {

final Node f = first;

if (f == null)

throw new NoSuchElementException();

return unlinkFirst(f);

}

//poll的时候如果没有元素返回null

public E pollFirst() {

final Node f = first;

return (f == null) ? null : unlinkFirst(f);

}

//删除首节点

private E unlinkFirst(Node f) {

//首节点的元素值

final E element = f.item;

//首节点的next指针

final Node next = f.next;

//首节点的值置为null,协助GC

f.item = null;

f.next = null; // help GC

//把首节点的next作为新的首节点

first = next;

//如果只有一个元素,删除了,就把last也置为null

//否则把next的前置指针置为null

if (next == null)

last = null;

else

next.prev = null;

//元素个数减一

size–;

//修改次数加一

modCount++;

//返回删除的元素

return element;

}

删除尾节点

//remove的时候如果没有元素抛出异常

public E removeLast() {

final Node l = last;

if (l == null)

throw new NoSuchElementException();

return unlinkLast(l);

}

//poll的时候如果没有元素返回null

public E pollLast() {

final Node l = last;

return (l == null) ? null : unlinkLast(l);

}

//删除尾节点

private E unlinkLast(Node l) {

//尾节点的元素值

final E element = l.item;

//尾节点的前置指针

final Node prev = l.prev;

//清空尾节点的内容,协助GC

l.item = null;

l.prev = null; // help GC

//让前置节点称为新的尾节点

last = prev;

//如果只有一个元素,删除了把first置为null

//否则把前置节点的next置为null

if (prev == null)

first = null;

else

prev.next = null;

//元素个数减一

size–;

//修改次数加一

modCount++;

//返回删除的元素

return element;

}

删除中间指定节点

//删除中间节点

public E remove(int index) {

//检查是否越界

checkElementIndex(index);

//删除指定index位置的节点

return unlink(node(index));

}

//删除指定节点

E unlink(Node x) {

// 节点x的元素值

final E element = x.item;

// x的前置节点

final Node next = x.next;

// x的后置节点

final Node prev = x.prev;

//如果前置节点为空

//说明是首节点,让first指向x的后置节点

//否则修改前置节点的next为x的后置节点

if (prev == null) {

first = next;

} else {

prev.next = next;

x.prev = null;

}

//如果后置节点为空

//说明是尾节点,让last指向x的前置节点

//否则修改后置节点prev为x的前置节点

if (next == null) {

last = prev;

} else {

next.prev = prev;

x.next = null;

}

//清空x的元素值,协助GC

x.item = null;

//元素个数减一

size–;

//修改次数加一

modCount++;

//返回删除的元素

return element;

}

总结

删除元素的三种方法都是典型的双链表删除元素的方法,大致流程如下图所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gFhZ2QFl-1641043621839)(LinkedList源码分析.assets/640)]

  • 在队列首尾删除元素很高效,时间复杂度为O(1)。

  • 在中间删除元素比较低效,首先要找到删除位置的节点,再修改前后指针,时间复杂度为O(n)。

7.清除方法


清除所有元素

public void clear() {

//为了让GC更快可以回收放置的元素,需要将node之间的引用关系赋空。

for (Node x = first; x != null; ) {

Node next = x.next;

x.item = null;

x.next = null;

x.prev = null;

x = next;

}

first = last = null;

//元素个数置为0

size = 0;

//修改次数加一

modCount++;

}

8.作为栈


LinkedList是双端队列,双端队列可以作为栈使用。

//元素入栈

public void push(E e) {

// 队列的头元素就是栈的栈顶元素

addFirst(e);

}

//删除栈顶元素并返回

本次面试答案,以及收集到的大厂必问面试题分享:

字节跳动超高难度三面java程序员面经,大厂的面试都这么变态吗?

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

t++;

}

8.作为栈


LinkedList是双端队列,双端队列可以作为栈使用。

//元素入栈

public void push(E e) {

// 队列的头元素就是栈的栈顶元素

addFirst(e);

}

//删除栈顶元素并返回

本次面试答案,以及收集到的大厂必问面试题分享:

[外链图片转存中…(img-XyDDz35r-1715418115816)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值