一文讲透链表操作,看完你也能轻松写出正确的链表代码,龙湖java面试几轮

链表的基本操作

=======

链表的基础操作同样的是增删改查,接下来我们就分别看一下如何对链表进行增删改查操作。

在进行增删改查之前,我们先初始化一个链表:

//定义链表节点

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 的代码,那么每次都要至少要反复考虑下面四种场景下代码能否正常工作:

  1. 链表为空时,能否达到预期效果。

  2. 链表只有一个 head 节点,能否达到预期效果。

  3. 链表只包含两个节点,能否达到预期效果。

  4. 如果逻辑处理在头节点或者尾结点(比如插入和删除操作),能否达到预期效果。

如果上面四种场景都没有问题,那么这段代码基本上就没有什么问题了。

链表的重要算法

=======

链表的操作非常考验编程者的思维,一不小心可能就会造成了指针丢失,或者边界处理错误的情况。在掌握了链表基本的增删改查之后,我们继续来看一下一些稍微复杂点的链表操作。

合并有序链表

======

leetcode 中的第 21 题:将两个升序链表合并为一个新的升序链表并返回,新链表是通过拼接给定的两个链表的所有节点组成的。

这道题不难,在 leetcode 中也是定义为简单级别,但是这道题的重点是有序列表,而且合并后仍然要保持有序,所以这时候新链表的头节点是谁我们也不知道,如果不使用任何技巧,直接写也能完成这道题目,但是却需要做各种判断,所以这里我们要介绍另一种技巧,那就是引入哨兵节点。

小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Java工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Java开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频

如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Java)
img

最后

小编精心为大家准备了一手资料

以上Java高级架构资料、源码、笔记、视频。Dubbo、Redis、设计模式、Netty、zookeeper、Spring cloud、分布式、高并发等架构技术

【附】架构书籍

  1. BAT面试的20道高频数据库问题解析
  2. Java面试宝典
  3. Netty实战
  4. 算法

BATJ面试要点及Java架构师进阶资料

0)]

最后

小编精心为大家准备了一手资料

[外链图片转存中…(img-BSz9DxpF-1711094476441)]

[外链图片转存中…(img-xcOqeXSE-1711094476441)]

以上Java高级架构资料、源码、笔记、视频。Dubbo、Redis、设计模式、Netty、zookeeper、Spring cloud、分布式、高并发等架构技术

【附】架构书籍

  1. BAT面试的20道高频数据库问题解析
  2. Java面试宝典
  3. Netty实战
  4. 算法

[外链图片转存中…(img-9KK3AXPX-1711094476442)]

BATJ面试要点及Java架构师进阶资料

[外链图片转存中…(img-ecNhWoAv-1711094476442)]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值