大二自学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 完成插入
- 遍历打印链表(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.反转链表与其实现过程
- 语句含义
if (head == null || head.next == null) {
return head;
}
- 判断链表是否为空,或者只有一个节点。
- 如果是,不需要反转,直接返回原头节点。
- 核心逻辑(最重要四步)
// 保存下一个节点(不保存会断链)
next = curr.next;
// 反转:当前节点指向前一个
curr.next = prev;
// prev 往前走一步
prev = curr;
// curr 往前走一步
curr = next;
- 你必须记住的关键点
- 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. curr = curr.next :指针往后走一步
2. curr.next != null :还没到最后一个节点
3. curr != null :当前节点有效,可以访问数据