单链表是否有环

                1,实现思路

如何判断一个单链表是否有环?
我们可以定义两个指针,第一个指针一次遍历一步,第二个指针一次遍历两步,如果第二个指针指向NULL,则单链表无环,如果第二个指针与第一个指针相遇,则说明有环。

                2,代码实现
LNode* HasCircle(LNode *phead)
{
    if(phead == NULL) return NULL;
    LNode *pFast = phead;
    LNode *pSlow = phead;

    while(pFast != NULL && pFast->next != NULL)
    {
        pFast = pFast->next->next;
        pSlow = pSlow->next;
        if(pFast == pSlow)
            return pFast;
    }
    return NULL;
}

如果有环,返回环的入口地址。

                3,实现思想

如果有环,通过返回相遇的节点,我们可以求出环的长度,然后我们定义两个指针,第一个指向头结点,并且向后遍历环的长度,第二个指针指向头结点,然后两个指针开始同时向后遍历,当两个指针相等的时候,此时的地址就是环的入口地址。

                4,代码实现
LNode *searchEntranceNode(LNode *phead)
{
    LNode *MeetNode = HasCircle(phead);
    if(MeetNode == NULL) return NULL;
    LNode *pNode1 = MeetNode->next;
    int length = 1;  //环的长度
    while(pNode1 != MeetNode)
    {
        pNode1 = pNode1->next;
        ++length;
    }
    pNode1 = phead;
    while(length--)
    {
        pNode1 = pNode1->next;
    }
    LNode *pNode2 = phead;
    while(pNode1 != pNode2)
    {
        pNode1 = pNode1->next;
        pNode2 = pNode2->next;
    }
    return pNode1;
}
                5,总结单链表

链表的操作在很多方面都会用到指针,如果一个指针不够用,可以用两个指针来实现,比如找单链表的第K个节点,找单链表的中间节点,找两个单链表的相交节点(下一篇博客实现)等等都会用到快慢指针,所以掌握快慢指针的用法,真的很重要!!!

判断单链表是否的方法有以下几种: #### 追及法(快慢指针法) 设置两个指针,一个是 `slow`,另一个是 `fast`。`slow` 一次走一个节点,`fast` 一次走两个节点,当 `fast` 追上 `slow` 即 `fast` 和 `slow` 重合时,说明链表中有 [^4]。 以下是Python代码示例: ```python class ListNode: def __init__(self, val=0, next=None): self.val = val self.next = next def hasCycle(head): slow = head fast = head while fast and fast.next: slow = slow.next fast = fast.next.next if slow == fast: return True return False ``` #### 哈希法 维护一个哈希表,遍历链表将每个节点的地址存入哈希表中,如果出现重复就代表链表有 [^4]。 以下是Python代码示例: ```python class ListNode: def __init__(self, val=0, next=None): self.val = val self.next = next def hasCycle(head): visited = set() while head: if head in visited: return True visited.add(head) head = head.next return False ``` #### 标记法 遍历单链表,将经过的节点都做标记,采用的方法是将遍历的节点都放入集合 `visited` 中,对每个节点判定是否在集合中出现过,若出现重复访问,则判定有。空间复杂度为 $O(n)$,时间复杂度为 $O(n^2)$ [^3]。 以下是Java代码示例: ```java import java.util.ArrayList; class Node { int val; Node next; Node(int x) { val = x; next = null; } } public class Main { private static boolean methodSecond(Node head) { ArrayList<Node> visited = new ArrayList<>(); while (head != null) { if (visited.contains(head)) { return true; } visited.add(head); head = head.next; } return false; } } ``` #### 链表合并转化法 先遍历第一个链表到它的尾部,然后将尾部的 `next` 指针指向第二个链表(尾部指针的 `next` 本来指向的是 `null`),这样两个链表就合成了一个链表,判断原来的两个链表是否相交也就转变成了判断新的链表是否的问题 [^1]。 #### 反转链表法 反转链表时,会用到3个指针,分别为指向遍历时当前的结点的 `current` 指针,指向反转后的子链表的头结点的指针 `temp`,及指向遍历时当前结点的下一个结点的 `next` 指针,如果在反转时,出现了 `next` 指向头结点的情况,那么肯定是有的 [^5]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值