java的单链表环操作有哪些

发布时间:2021-12-27 16:54:18 作者:iii
来源:亿速云 阅读:194
# Java的单链表环操作有哪些

## 目录
1. [单链表与环的基本概念](#单链表与环的基本概念)
2. [检测单链表是否存在环](#检测单链表是否存在环)
   - [哈希表法](#哈希表法)
   - [快慢指针法](#快慢指针法)
3. [计算环的长度](#计算环的长度)
4. [寻找环的入口节点](#寻找环的入口节点)
5. [断开链表中的环](#断开链表中的环)
6. [完整代码示例](#完整代码示例)
7. [应用场景与总结](#应用场景与总结)

---

## 单链表与环的基本概念
单链表是由节点组成的线性数据结构,每个节点包含:
- **数据域**:存储实际数据
- **指针域**:指向下一个节点的引用

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

链表环指链表中某个节点的next指针指向了链表中它前面的某个节点,形成闭环。

java的单链表环操作有哪些


检测单链表是否存在环

哈希表法

时间复杂度: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;
}

计算环的长度

  1. 先使用快慢指针找到相遇点
  2. 从相遇点开始计数,直到再次回到该点
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 + kLa = (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;
    }
}

应用场景与总结

典型应用场景

  1. 内存管理中的循环引用检测
  2. 网络路由检测环路
  3. 并发编程中的死锁检测

性能对比

方法 时间复杂度 空间复杂度 适用场景
哈希表法 O(n) O(n) 需要记录访问路径
快慢指针法 O(n) O(1) 内存受限环境

总结

  1. 快慢指针法是解决链表环问题的黄金标准
  2. 理解数学原理比记忆代码更重要
  3. 实际开发中需根据场景选择合适方法

扩展思考:如何将这些方法应用于双向链表的环检测? “`

注:实际使用时需要: 1. 替换示意图URL为真实图片 2. 根据具体需求调整代码细节 3. 补充更多实际案例和性能测试数据 4. 扩展部分可增加多语言实现对比

推荐阅读:
  1. 链表是否有环
  2. 单链表逆序操作

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

java

上一篇:如何实现OCTO2.0 的探索与实践

下一篇:SAP HU上面的Obj.to Which HU Belongs栏位是怎样的

相关阅读

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

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