Java链表核心知识

1 阅读4分钟

大二自学Java链表的实现:从定义原理到代码实现的踩坑总结

1. 链表节点类(ListNode)

  • 用类表示链表的一个节点 ​
  • 包含两个部分: ​
  •  data :数据域,存储具体数据 ​
  •  next :指针域,指向下一个节点
static class ListNode {//通过类表示链表的节点
    private int data;//存储数据,链表的数据域
    private ListNode next;//链表的指针域

    public ListNode(int data) {
        this.data = data;
        this.next = null;
    }

2. 尾插法添加节点(insertNode)

  • 从头节点开始,找到最后一个节点 ​
  • 把新节点挂在最后面
private static void insertNode(ListNode node, int data) {
    if (node == null) {
        return;
    }//创建一个新链表,把这个链表插入原先链表
    ListNode newNode = new ListNode(data);
    ListNode curr = node;//创建一个新指针curr指向新链表的头节点
    while (curr.next != null) {//指针移动
        curr = curr.next;
    }
    curr.next = newNode;//赋值过程
}

  核心逻辑:

  •  curr = curr.next :指针向后移动 ​
  •  curr.next != null :判断是否还有下一个节点 ​
  • 最后让  curr.next = newNode  完成插入

 

  1. 遍历打印链表(printNode)
  • 从头节点开始,依次输出每个节点的数据 ​
  • 直到节点为  null  结束
private static void printNode(ListNode node) {
   if(node == null) {//空链表判断
       return;
   }
   ListNode curr = node;
   while (curr != null) {
       System.out.print(curr.data + " ");
       curr = curr.next;
   }
   System.out.println();//换行
}

4. 手动创建 & 修改链表

(1)手动创建链表并打印

System.out.println("================originalNode================");
ListNode head = new ListNode(1);
head.next = new ListNode(2);//添加一个新节点2
head.next.next = new ListNode(3);
head.next.next.next = new ListNode(4);
head.next.next.next.next = new ListNode(5);
printNode(head);//打印原节点
  • 一个一个用  next  连接起来 ​
  • 形成: 1 → 2 → 3 → 4 → 5 

(2)手动断开 & 插入节点

  • 先移动指针到指定位置 ​
  • 用  next = null  断开后面 ​
  • 再用  next = newNode  接入新节点

6. 删除指定节点

核心逻辑:找到目标节点的前一个节点,将它的 next 指针指向目标节点的下一个节点,把目标节点从链中“跳过”。

代码实现

private static void deleteNode(ListNode head, int targetData) {
    if (head == null) {
        return;
    }
    // 如果要删头节点
    if (head.data == targetData) {
        head = head.next;
        return;
    }
    ListNode curr = head;
    // 找目标节点的前一个
    while (curr.next != null && curr.next.data != targetData) {
        curr = curr.next;
    }
    // 如果找到目标节点
    if (curr.next != null) {
        curr.next = curr.next.next;
    }
}

7.反转链表与其实现过程

  1. 语句含义
if (head == null || head.next == null) {
       return head;
   }
  • 判断链表是否为空,或者只有一个节点。 ​
  • 如果是,不需要反转,直接返回原头节点。
  1. 核心逻辑(最重要四步)
// 保存下一个节点(不保存会断链)
next = curr.next;

// 反转:当前节点指向前一个
curr.next = prev;

// prev 往前走一步
prev = curr;

// curr 往前走一步
curr = next;
  1. 你必须记住的关键点
  • prev 一开始是 null,因为第一个节点反转后变成最后一个节点,指向 null。 ​
  • next 必须先保存,否则  curr.next = prev  之后,后面的链表就找不到了。 ​
  • 循环结束:-  curr == null  ​
  •  prev  是新的头节点。

一句话理解:

先存后路 → 再掉头 → 前指针跟上 → 后指针跟上  

注意点:

一定要先处理头节点的特殊情况,不然会出现空指针或者删不掉头节点的问题。

8. 部分运行流程展示

1. 手动创建  1→2→3→4→5  并打印

2. 手动修改链表,断开、插入节点

3. 使用封装好的  insertNode  尾插  10→20→30→40→50 

4. 打印结果,观察链表变化

System.out.println("==============revisedNode==============");
 ListNode temp = head;//定义第二个指针temp指向1节点
 ListNode temp2 = new ListNode(3);//可修改具体指向节点,将节点数据放在括号里面
 temp = temp.next;//移动指针到下一位,也就是节点2
 temp.next = null;//从节点2开始断开链表(通过让当前temp的指针域指向空)
temp.next = new ListNode(100); //通过这种方法来实现链表的插入,但也需要将100节点的next指向2节点
 temp = temp.next;//指针后移一位
 System.out.println(temp.data);//输出指针当前指向的数据(实验判断逻辑是否正确)
  head.next.next.next=null;//3节点的指针指向null,就是把3节点后面的内容断开,由结果可看出这行代码没有实际意义
 printNode(head);//打印修改后的节点

6.在main方法中调用方法

System.out.println("================insertNode================");
ListNode root = new ListNode(10);//创建一个新链表,这是个单节点链表
insertNode(root,20);
insertNode(root,30);
insertNode(root,40);
insertNode(root,50);
printNode(root);
System.out.println("===========================================");
  1. 链表三句核心口诀(背会就会写)

1.  curr = curr.next :指针往后走一步

2.  curr.next != null :还没到最后一个节点

3.  curr != null :当前节点有效,可以访问数据