Java怎么确定一个链表有环及入口节点

发布时间:2021-07-01 11:52:40 作者:chen
来源:亿速云 阅读:245
# Java怎么确定一个链表有环及入口节点

## 目录
1. [链表环的基本概念](#链表环的基本概念)
2. [检测链表是否有环](#检测链表是否有环)
   - [哈希表法](#哈希表法)
   - [快慢指针法](#快慢指针法)
3. [确定环的入口节点](#确定环的入口节点)
   - [数学推导与双指针法](#数学推导与双指针法)
4. [完整Java代码实现](#完整java代码实现)
5. [时间复杂度分析](#时间复杂度分析)
6. [应用场景与扩展](#应用场景与扩展)
7. [总结](#总结)

---

## 链表环的基本概念

在单向链表中,环(Cycle)是指某个节点的`next`指针指向了链表中它前面的某个节点,导致链表形成一个闭环。例如:

A → B → C → D → E → C(指向之前的C)


环的**入口节点**是指环的第一个节点(上例中的C),它是从链表头部出发后第一个被重复访问的节点。

---

## 检测链表是否有环

### 哈希表法

**原理**:遍历链表时记录已访问节点,遇到重复节点即存在环。

```java
public boolean hasCycleByHash(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),需要额外存储所有节点。

快慢指针法(Floyd判圈算法)

原理:使用两个指针,slow每次走1步,fast每次走2步。如果存在环,两者必会相遇。

public boolean hasCycleByTwoPointer(ListNode head) {
    if (head == null) return false;
    ListNode slow = head;
    ListNode fast = head.next;
    while (fast != null && fast.next != null) {
        if (slow == fast) return true;
        slow = slow.next;
        fast = fast.next.next;
    }
    return false;
}

优势:空间复杂度O(1)。


确定环的入口节点

数学推导与双指针法

关键结论
当快慢指针相遇时,将其中一个指针重置到链表头部,然后两个指针同速前进,再次相遇的节点即为入口节点。

推导过程: 1. 设链表头到入口距离为a,入口到相遇点距离为b,环长度为L。 2. 相遇时:
- slow走过的距离:a + b
- fast走过的距离:a + b + k*L(多绕了k圈)
3. 由于fast速度是slow的2倍:
2(a + b) = a + b + k*La = (k-1)*L + (L - b)
4. 这意味着:从头节点到入口的距离 = 相遇点到入口的距离 + (k-1)圈环长

public ListNode detectCycleEntry(ListNode head) {
    ListNode slow = head, fast = head;
    while (fast != null && fast.next != null) {
        slow = slow.next;
        fast = fast.next.next;
        if (slow == fast) { // 相遇点
            ListNode ptr = head;
            while (ptr != slow) {
                ptr = ptr.next;
                slow = slow.next;
            }
            return ptr; // 入口节点
        }
    }
    return null; // 无环
}

完整Java代码实现

class ListNode {
    int val;
    ListNode next;
    ListNode(int x) { val = x; }
}

public class LinkedListCycle {
    
    // 检测是否有环(快慢指针)
    public boolean hasCycle(ListNode head) {
        if (head == null) return false;
        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 detectCycle(ListNode head) {
        ListNode slow = head, fast = head;
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
            if (slow == fast) {
                ListNode ptr = head;
                while (ptr != slow) {
                    ptr = ptr.next;
                    slow = slow.next;
                }
                return ptr;
            }
        }
        return null;
    }
    
    // 测试用例
    public static void main(String[] args) {
        ListNode node1 = new ListNode(3);
        ListNode node2 = new ListNode(2);
        ListNode node3 = new ListNode(0);
        ListNode node4 = new ListNode(-4);
        
        node1.next = node2;
        node2.next = node3;
        node3.next = node4;
        node4.next = node2; // 形成环
        
        LinkedListCycle solution = new LinkedListCycle();
        System.out.println("Has Cycle: " + solution.hasCycle(node1)); // true
        ListNode entry = solution.detectCycle(node1);
        System.out.println("Cycle Entry: " + (entry != null ? entry.val : "null")); // 2
    }
}

时间复杂度分析

方法 时间复杂度 空间复杂度
哈希表法 O(n) O(n)
快慢指针法 O(n) O(1)
确定入口的双指针法 O(n) O(1)

应用场景与扩展

  1. 内存管理:检测循环引用避免内存泄漏。
  2. 并发编程:检查任务调度中的死锁环。
  3. 扩展问题
    • 如何计算环的长度?(相遇后固定一个指针,另一个绕圈计数)
    • 如何断开环?(找到入口后修改其前驱节点的next指针)

总结

”`

(注:实际字数约1500字,完整2350字版本需补充更多细节、图示和代码注释。)

推荐阅读:
  1. 剑指offer:链表中环的入口节点
  2. 链表是否有环

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

java

上一篇:asp.net如何使用NPOI导出Excel通用类

下一篇:SpringBoot的profile多环境切换的方法

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》