//通过下标获取某个node 的时候,(增、查 ),会根据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;
}
}
checkPositionIndex(index)
private void checkPositionIndex(int index) {
if (!isPositionIndex(index))
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
private boolean isPositionIndex(int index) {
return index >= 0 && index <= size; //插入时的检查,下标可以是size [0,size]
}
小结:
-
链表批量增加,是靠for循环遍历原数组,依次执行插入节点操作。对比ArrayList是通过System.arraycopy完成批量增加的
-
通过下标获取某个node 的时候,会根据index处于前半段还是后半段 进行一个折半,以提升查询效率
add
添加单个元素
add(E e)
//在尾部插入一个节点: add
public boolean add(E e) {
linkLast(e);
return true;
}
linkLast(e)
//生成新节点 并插入到 链表尾部, 更新 last/first 节点。
void linkLast(E e) {
final Node l = last; //记录原尾部节点
final Node newNode = new Node<>(l, e, null);//以原尾部节点为新节点的前置节点
last = newNode;//更新尾部节点
if (l == null)//若原链表为空链表,需要额外更新头结点
first = newNode;
else//否则更新原尾节点的后置节点为现在的尾节点(新节点)
l.next = newNode;
//size和modCount自增。
size++;
modCount++;
}
添加单个元素并且带上位置
add(int index, E element)
//在指定下标,index处,插入一个节点
public void add(int index, E element) {
checkPositionIndex(index);//检查下标是否越界[0,size]
if (index == size)//在尾节点后插入
linkLast(element);
else//在中间插入
linkBefore(element, node(index));
}
linkBefore(element, node(index))
//在succ节点前,插入一个新节点e
void linkBefore(E e, Node succ) {
// assert succ != null;
//保存succ的前置节点
final Node pred = succ.prev;
//以前置和后置节点和元素值e 构建一个新节点
final Node newNode = new Node<>(pred, e, succ);
//新节点new是原节点succ的前置节点
succ.prev = newNode;
if (pred == null)//如果之前的前置节点是空,说明succ是原头结点。所以新节点是现在的头结点
first = newNode;
else//否则构建前置节点的后置节点为new
pred.next = newNode;
size++;
modCount++;
}
小结:
- 增一定会修改modCount
remove
按照位置删除结点
remove(int index)
//删:remove目标节点
public E remove(int index) {
checkElementIndex(index);//检查是否越界 下标[0,size)
return unlink(node(index));//从链表上删除某节点
}
unlink(node(index))
//从链表上删除x节点
E unlink(Node x) {
// assert x != null;
final E element = x.item; //当前节点的元素值
final Node next = x.next; //当前节点的后置节点
final Node prev = x.prev;//当前节点的前置节点
if (prev == null) { //如果前置节点为空(说明当前节点原本是头结点)
first = next; //则头结点等于后置节点
} else {
prev.next = next;
x.prev = null; //将当前节点的 前置节点置空 将节点置空,方便GC
}
if (next == null) {//如果后置节点为空(说明当前节点原本是尾节点)
last = prev; //则 尾节点为前置节点
} else {
next.prev = prev;
x.next = null;//将当前节点的 后置节点置空 将节点置空,方便GC
}
x.item = null; //将当前元素值置空
size–; //修改数量
modCount++; //修改modCount
return element; //返回取出的元素值
}
checkElementIndex(index)
private void checkElementIndex(int index) {
if (!isElementIndex(index))
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
//下标[0,size)
private boolean isElementIndex(int index) {
return index >= 0 && index < size;
}
直接删除某个结点
remove(Object o)
//因为要考虑 null元素,也是分情况遍历
public boolean remove(Object o) {
if (o == null) {//如果要删除的是null节点(从remove和add 里 可以看出,结点允许元素为null)
//遍历每个节点 对比
for (Node x = first; x != null; x = x.next) {
if (x.item == null) {
unlink(x);
return true;
}
}
} else {
for (Node x = first; x != null; x = x.next) {
if (o.equals(x.item)) {
unlink(x);
return true;
}
}
}
return false;
}
小结
-
删也一定会修改modCount
-
按下标删,也是先根据index找到Node,然后去链表上unlink掉这个Node。
-
按元素删,会先去遍历链表寻找是否有该Node,考虑到允许null值,所以会遍历两遍,然后再去unlink它
-
扩展:遍历链表的方式
for (Node x = first; x != null; x = x.next) {
…
}
Node x = first;
while(x!=null){
x = x.next;
}
set
public E set(int index, E element) {
checkElementIndex(index); //检查越界[0,size)
Node x = node(index);//取出对应的Node
E oldVal = x.item;//保存旧值 供返回
x.item = element;//用新值覆盖旧值
return oldVal;//返回旧值
}
改也是先根据index找到Node,然后替换值,改 不会修改modCount
get
根据index查询节点
get(int index)
public E get(int index) {
checkElementIndex(index);//判断是否越界 [0,size)
return node(index).item; //调用node()方法 取出 Node节点,
}
根据节点对象,查询下标
indexOf(Object o)
public int indexOf(Object o) {
int index = 0;
if (o == null) {//如果目标对象是null
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。


既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)
最后
我想问下大家当初选择做程序员的初衷是什么?有思考过这个问题吗?高薪?热爱?
既然入了这行就应该知道,这个行业是靠本事吃饭的,你想要拿高薪没有问题,请好好磨练自己的技术,不要抱怨。有的人通过培训可以让自己成长,有些人可以通过自律强大的自学能力成长,如果你两者都不占,还怎么拿高薪?
架构师是很多程序员的职业目标,一个好的架构师是不愁所谓的35岁高龄门槛的,到了那个时候,照样大把的企业挖他。为什么很多人想进阿里巴巴,无非不是福利待遇好以及优质的人脉资源,这对个人职业发展是有非常大帮助的。
如果你也想成为一名好的架构师,那或许这份Java核心架构笔记你需要阅读阅读,希望能够对你的职业发展有所帮助。
中高级开发必知必会:

《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》,点击传送门即可获取!
7895254671a72faed303032d36.jpg" alt=“img” style=“zoom: 33%;” />
最后
我想问下大家当初选择做程序员的初衷是什么?有思考过这个问题吗?高薪?热爱?
既然入了这行就应该知道,这个行业是靠本事吃饭的,你想要拿高薪没有问题,请好好磨练自己的技术,不要抱怨。有的人通过培训可以让自己成长,有些人可以通过自律强大的自学能力成长,如果你两者都不占,还怎么拿高薪?
架构师是很多程序员的职业目标,一个好的架构师是不愁所谓的35岁高龄门槛的,到了那个时候,照样大把的企业挖他。为什么很多人想进阿里巴巴,无非不是福利待遇好以及优质的人脉资源,这对个人职业发展是有非常大帮助的。
如果你也想成为一名好的架构师,那或许这份Java核心架构笔记你需要阅读阅读,希望能够对你的职业发展有所帮助。
中高级开发必知必会:
[外链图片转存中…(img-m2fEgezR-1712072833261)]
《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》,点击传送门即可获取!
文章详细介绍了Java链表中节点的增删查操作,包括通过索引高效查询、批量增加策略,以及如何利用modCount跟踪修改。讨论了与ArrayList的区别,强调了链表操作的原理和性能优化。
157

被折叠的 条评论
为什么被折叠?



