链表的基本操作
=======
链表的基础操作同样的是增删改查,接下来我们就分别看一下如何对链表进行增删改查操作。
在进行增删改查之前,我们先初始化一个链表:
//定义链表节点
public class ListNode {
public int val;//节点中的值
public ListNode next;//指向下一个节点的指针
public int getVal(){
return this.val;
}
ListNode(int x) {
val = x;
next = null;
}
}
//根据数组初始化一个链表
package com.lonely.wolf.note.list;
public class ListNodeInit {
public static ListNode initLinkedList(int[] array) {
ListNode head = null, cur = null;
for (int i = 0; i < array.length; i++) {
ListNode newNode = new ListNode(array[i]);
newNode.next = null;
if (i == 0) {//初始化头节点
head = newNode;
cur = head;
} else {//继续一个个往后插入节点
cur.next = newNode;
cur = newNode;
}
}
return head;
}
}
获取链表长度
======
在单向链表中,获取一个链表的长度需要从头节点开始往后遍历,直到链表尾部。所以获取一个链表的长度时间复杂度也是 O(n):
public static int getListLength(ListNode head){
int length = 0;
while (null != head){
length++;
head = head.next;
}
return length;
}
查找节点
====
假如说需要查找一个指定节点,或者说查找第 N 个节点,查找方式也是和获取链表长度一样,从 head 节点开始遍历,然后进行对比或者计数,直到找到需要的节点,所以查找一个节点的最坏时间复杂度也是 O(n)。
新增节点
====
假如说我们需要在指定链表的指定位置插入一个节点,那么这时候我们需要考虑以下几点:
-
当前插入的位置是否超出了链表的长度。
-
当前指定的链表是否为空。
-
当前插入链表的位置是链表的头部,尾部,还是中间位置。
下面就是一个往指定链表中指定位置插入一个元素的示例:
public static ListNode insertNode(ListNode head, ListNode insertNode, int position) {
if (null == head){//需要注意当前链表为空的情况
return insertNode;
}
int size = ListNodeInit.getListLength(head);//获取链表长度
if (position < 0 || position > size + 1){//处理越界
return head;
}
if (position == 1){//插入头部(对链表一般从 1 开始)
insertNode.next = head;
head = insertNode;
return head;
}
//假如不是插入链表头部,那么这时候我们需要找到插入位置的前一个节点
ListNode prevNode = head;
int i = 1;
while (i < position-1) {//遍历到position的前一个节点
prevNode = prevNode.next;
i++;
}
//注意这里的插入操作,要有器注意指针丢失,如果后面这两句话反一下,那么就会造成链表断裂
insertNode.next = prevNode.next;//1
prevNode.next = insertNode;//2
return head;
}
我们以文中开头的单向链表为例子,假如要在第 4 个 位置插入一个 val=5 的节点,这时候我们需要先找到节点 3,也就是上面示例中的 preNode 节点,这时候假如我们先执行上面注释为 2 的代码:preNode.next = insertNode,那么就会出现下图中情况(虚线的指针表示已经被被改变):
这时候我们发现原链表被断开,也就是节点 4 已经找不到了,所以插入节点的时候,一定要将新节点和原链表先接上才能防止指针丢失。
这里要划个重点,请注意链表操作一定要谨防指针丢失。
删除节点
====
删除一个节点和插入一个节点类似,也需要考虑各种边界情况,大家不要以为这些边界判断都是小事,事实在面试中写一个算法,最为重要的就是边界的判断,边界判断错误,可能运行就报错,运行报错可能面试就 over 了。
还是以文中开始的单向链表为例,假如要删除节点 3,那么这时候 pNode 就是 2,deleteNode 就是 3,要把节点 3 删除的第一步就是把图中指针 p1 先指向 4,然后再将指针 p2 断开,即可完成节点的删除。
下面就是删除一个节点的示例:
public static ListNode deleteNode(ListNode head,int position) {
if (null == head){//链表为空
return null;
}
int length = ListNodeInit.getListLength(head);//获取链表长度
if (position <= 0 || position > length){//删除位置无效
return head;
}
//删除头部节点
ListNode pNode = head;
if (position == 1){
head.next = null;//断开原head,不断也行,断开可以防止内存泄露
return pNode.next;//设置新head
}
int count = 1;
while (count < position - 1){//找到删除节点的前一个节点
pNode = pNode.next;
count++;
}
//断开流程见下图
ListNode deleteNode = pNode.next;//找到需要删除的节点
pNode.next = deleteNode.next;
deleteNode.next = null;//断开删除节点和链表的联系,不断也行,断开可以防止内存泄露
return head;
}
更新节点
====
如果掌握了前面的查询,插入,删除操作,那么更新就简单了,如果只是更新节点的 val,那么遍历找到节点直接替换即可,如果说要改变某一个节点的位置,那么可以先删除原节点,再插入即可完成。
如何写出 Bug Free 的链表代码
===================
操作链表的时候如果想写出一段 BugFree 的代码,那么每次都要至少要反复考虑下面四种场景下代码能否正常工作:
-
链表为空时,能否达到预期效果。
-
链表只有一个 head 节点,能否达到预期效果。
-
链表只包含两个节点,能否达到预期效果。
-
如果逻辑处理在头节点或者尾结点(比如插入和删除操作),能否达到预期效果。
如果上面四种场景都没有问题,那么这段代码基本上就没有什么问题了。
链表的重要算法
=======
链表的操作非常考验编程者的思维,一不小心可能就会造成了指针丢失,或者边界处理错误的情况。在掌握了链表基本的增删改查之后,我们继续来看一下一些稍微复杂点的链表操作。
合并有序链表
======
leetcode 中的第 21 题:将两个升序链表合并为一个新的升序链表并返回,新链表是通过拼接给定的两个链表的所有节点组成的。
这道题不难,在 leetcode 中也是定义为简单级别,但是这道题的重点是有序列表,而且合并后仍然要保持有序,所以这时候新链表的头节点是谁我们也不知道,如果不使用任何技巧,直接写也能完成这道题目,但是却需要做各种判断,所以这里我们要介绍另一种技巧,那就是引入哨兵节点。
小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Java工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Java开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Java)
最后
小编精心为大家准备了一手资料
以上Java高级架构资料、源码、笔记、视频。Dubbo、Redis、设计模式、Netty、zookeeper、Spring cloud、分布式、高并发等架构技术
【附】架构书籍
- BAT面试的20道高频数据库问题解析
- Java面试宝典
- Netty实战
- 算法
BATJ面试要点及Java架构师进阶资料
0)]
最后
小编精心为大家准备了一手资料
[外链图片转存中…(img-BSz9DxpF-1711094476441)]
[外链图片转存中…(img-xcOqeXSE-1711094476441)]
以上Java高级架构资料、源码、笔记、视频。Dubbo、Redis、设计模式、Netty、zookeeper、Spring cloud、分布式、高并发等架构技术
【附】架构书籍
- BAT面试的20道高频数据库问题解析
- Java面试宝典
- Netty实战
- 算法
[外链图片转存中…(img-9KK3AXPX-1711094476442)]
BATJ面试要点及Java架构师进阶资料
[外链图片转存中…(img-ecNhWoAv-1711094476442)]