您好,登录后才能下订单哦!
密码登录
登录注册
点击 登录注册 即表示同意《亿速云用户服务条款》
# Java的单链表环操作有哪些
## 目录
1. [单链表与环的基本概念](#单链表与环的基本概念)
2. [检测单链表是否存在环](#检测单链表是否存在环)
- [哈希表法](#哈希表法)
- [快慢指针法](#快慢指针法)
3. [计算环的长度](#计算环的长度)
4. [寻找环的入口节点](#寻找环的入口节点)
5. [断开链表中的环](#断开链表中的环)
6. [完整代码示例](#完整代码示例)
7. [应用场景与总结](#应用场景与总结)
---
## 单链表与环的基本概念
单链表是由节点组成的线性数据结构,每个节点包含:
- **数据域**:存储实际数据
- **指针域**:指向下一个节点的引用
```java
class ListNode {
int val;
ListNode next;
ListNode(int x) { val = x; }
}
链表环指链表中某个节点的next指针指向了链表中它前面的某个节点,形成闭环。
时间复杂度:O(n)
空间复杂度:O(n)
public boolean hasCycle(ListNode head) {
Set<ListNode> visited = new HashSet<>();
while (head != null) {
if (visited.contains(head)) {
return true;
}
visited.add(head);
head = head.next;
}
return false;
}
时间复杂度:O(n)
空间复杂度:O(1)
public boolean hasCycle(ListNode head) {
if (head == null) return false;
ListNode slow = head;
ListNode fast = head.next;
while (slow != fast) {
if (fast == null || fast.next == null) {
return false;
}
slow = slow.next;
fast = fast.next.next;
}
return true;
}
public int cycleLength(ListNode head) {
ListNode meetNode = detectMeetingNode(head);
if (meetNode == null) return 0;
int length = 1;
ListNode current = meetNode.next;
while (current != meetNode) {
length++;
current = current.next;
}
return length;
}
private ListNode detectMeetingNode(ListNode head) {
// 快慢指针实现...
}
数学推导:
设链表头到入口距离为a,入口到相遇点距离为b,环长为L
根据快慢指针速度关系可得:2(a+b) = a + b + kL
⇒ a = (k-1)L + (L-b)
public ListNode detectCycleStart(ListNode head) {
ListNode meetNode = detectMeetingNode(head);
if (meetNode == null) return null;
ListNode ptr1 = head;
ListNode ptr2 = meetNode;
while (ptr1 != ptr2) {
ptr1 = ptr1.next;
ptr2 = ptr2.next;
}
return ptr1;
}
找到入口节点后,将其前驱节点的next置为null
public void breakCycle(ListNode head) {
ListNode cycleStart = detectCycleStart(head);
if (cycleStart == null) return;
ListNode current = cycleStart;
while (current.next != cycleStart) {
current = current.next;
}
current.next = null;
}
public class LinkedListCycleOperations {
// 节点定义
static class ListNode {
int val;
ListNode next;
ListNode(int x) { val = x; }
}
// 检测环
public boolean hasCycle(ListNode head) {
ListNode slow = head, fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast) return true;
}
return false;
}
// 找环入口
public ListNode detectCycleStart(ListNode head) {
ListNode meetNode = getMeetingNode(head);
if (meetNode == null) return null;
ListNode ptr1 = head, ptr2 = meetNode;
while (ptr1 != ptr2) {
ptr1 = ptr1.next;
ptr2 = ptr2.next;
}
return ptr1;
}
private ListNode getMeetingNode(ListNode head) {
ListNode slow = head, fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast) return slow;
}
return null;
}
// 计算环长
public int getCycleLength(ListNode head) {
ListNode meetNode = getMeetingNode(head);
if (meetNode == null) return 0;
int length = 1;
ListNode current = meetNode.next;
while (current != meetNode) {
length++;
current = current.next;
}
return length;
}
// 断环
public void breakCycle(ListNode head) {
ListNode cycleStart = detectCycleStart(head);
if (cycleStart == null) return;
ListNode prev = cycleStart;
while (prev.next != cycleStart) {
prev = prev.next;
}
prev.next = null;
}
}
方法 | 时间复杂度 | 空间复杂度 | 适用场景 |
---|---|---|---|
哈希表法 | O(n) | O(n) | 需要记录访问路径 |
快慢指针法 | O(n) | O(1) | 内存受限环境 |
扩展思考:如何将这些方法应用于双向链表的环检测? “`
注:实际使用时需要: 1. 替换示意图URL为真实图片 2. 根据具体需求调整代码细节 3. 补充更多实际案例和性能测试数据 4. 扩展部分可增加多语言实现对比
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。