单链表经典题集之带环问题

1.判断单链表是否带环

这个题一开始你可能会想,这不是很简单吗,直接用一个指针遍历一编,如果返回值为空就没有带环,如果死循环就带环。EMmmmmm,这样做没毛病,但是我们可以不这么暴力也可以判断链表是否带环。使用追赶的方法,设定两个指针slow、fast,从头指针开始,每次分别前进1步、2步。如存在环,则两者相遇;如不存在环,fast遇到NULL退出。

SListNode *SListIsCycle(SListNode *list)
{
    SListNode *slow = list, *fast = list;
    assert(list);
    while ((fast != NULL) &&( fast->_next != NULL)) //如果无环,则fast先走到终点为空,当链表长度为奇数时,fast->Next为空 ,当链表长度为偶数时,fast为空  
        {

            fast = fast->_next->_next;
            slow = slow->_next;
            if (fast == slow)
            {
                break;
            }
        }
        if (fast == NULL || fast->_next == NULL)
        {
            return NULL;
        }
        else
        {
            return fast;
        }
}

2. 假设单链表带环,求环长度

这个问题在上一道问题的基础上,上一道题找到并返回了fast指针和slow指针相遇的链表指针,而相遇点一定在环内,所以我们可以继续让fast和slow指针在相遇点同时走,但是每次slow指针走一步,fast指针走两步,当他们再次相遇时,slow指针刚好绕环走了一圈。

int SListCycleLen(SListNode* meetNode)
{
    int len = 0;
    SListNode* meet = SListIsCycle(meetNode),*fast=meet,*slow=meet;//调用上一个函数找到fast和slow指针的相遇点
    assert(meet&&meetNode);
    while (1)
    {
        slow = slow->_next;
        fast = fast->_next->_next;
        len++;
        if (slow == fast)//当fast、slow相遇,返回len
        {
            return len;
        }
    }
}

这里写图片描述

3. 如果单链表带环,求环的入口

emmm,这是一道数学题,我们假设链表长度L,环长度R,入口点到链表头结点的距离a,入口点到快慢指针相遇点的距离x,现在假设慢指针走了S步与快指针相遇,
s = a + x;
那么快指针每次走了2S步,
2s = a + nr + x; //nr是有可能a很长在slow指针还没有入环时fast已经在环里走了很多圈
就可以得到:a + x = nr;
a = nr - x;
可以看出来,头节点到入口点的距离=相遇点到入口点的距离,那我们让两个指针,一个从相遇点走,一个从头节点走,最后一定在入口点相遇。

int  SListEntryNode(SListNode* list, SListNode* meetNode)//传参传的是头指针和相遇点的指针
{
    assert(list&&meetNode);
    SListNode* p = list, *q = meetNode;
    while (1)
    {
        p = p->_next;
        q = q->_next;
        if (p == q)
        {
            return q->_data ;
        }
    }
}

完整的代码:

#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
typedef int DataType;
typedef struct SListNode
{
    struct SListNode *_next;
    DataType _data;
}SListNode;
//创建结点
SListNode *BuySListNode(DataType x)
{

    SListNode *Lhead = (SListNode *)malloc(sizeof(SListNode));
    Lhead->_data = x;
    Lhead->_next = NULL;
    return Lhead;
}
//销毁链表
void SListDestory(SListNode* *PHead)
{
    assert(*PHead);
    SListNode *pre = *PHead, *p = (*PHead)->_next;
    while (p != NULL)
    {
        free(pre);
        pre = p;
        p = pre->_next;
    }
    free(pre);
}
//尾插数据
void SListPushBack(SListNode* *ppHead, DataType x)
{
    SListNode* s = NULL;
    if (!(*ppHead))
    {
        (*ppHead) = BuySListNode(x);
    }
    else
    {
        s = *ppHead;
        while (s->_next)
        {
            s = s->_next;
        }
        s->_next = BuySListNode(x);
    }
}
//单链表变循环单链表
SListNode *DanHuan(SListNode * *PHead)
{
    SListNode *p = *PHead;
    assert(*PHead);
    while (p->_next)
    {
        p = p->_next;
    }
    p->_next = (*PHead)->_next->_next;
    return PHead;
}
//判断单链表是否带环
SListNode *SListIsCycle(SListNode *list)
{
    SListNode *slow = list, *fast = list;
    assert(list);
    while ((fast != NULL) && (fast->_next != NULL))
    {

        fast = fast->_next->_next;
        slow = slow->_next;
        if (fast == slow)
        {
            break;
        }
    }
    if (fast == NULL || fast->_next == NULL)
    {
        return NULL;
    }
    else
    {
        return fast;
    }
}
//若单链表带环,求环长度
int SListCycleLen(SListNode* meetNode)
{
    int k = 0;
    SListNode* meet = SListIsCycle(meetNode), *fast = meet, *slow = meet;
    assert(meet&&meetNode);
    while (1)
    {
        slow = slow->_next;
        fast = fast->_next->_next;
        k++;
        if (slow == fast)
        {
            return k;
        }
    }
}
//求环的入口
int  SListEntryNode(SListNode* list, SListNode* meetNode)
{
    assert(list&&meetNode);
    SListNode* p = list, *q = meetNode;
    while (1)
    {
        p = p->_next;
        q = q->_next;
        if (p == q)
        {
            return q->_data;
        }
    }
}
int main()
{
    SListNode *PHead = NULL;
    SListNode *PHead1 = NULL;
    SListPushBack(&PHead, 1);
    SListPushBack(&PHead, 3);
    SListPushBack(&PHead, 5);
    SListPushBack(&PHead, 6);
    SListPushBack(&PHead, 7);
    SListPushBack(&PHead, 8);//用尾插法形成一个单链表
    printf("*********************\n");
    //if (SListIsCycle(DanHuan(&PHead)) == 0)//判断单链表是否有环
    //{
    //printf("NO\n");
    //}
    //else
    //{
    //printf("Yes\n");
    //}//在调试下面两个函数时,判断单链表是否有环应当屏蔽掉
    printf("*********************\n");
    printf("%d\n", SListCycleLen(DanHuan(&PHead)));//如果有环,求环长
    printf("*********************\n");
    printf("%d\n", SListEntryNode(PHead, SListIsCycle(PHead)));//求环的入口点
    system("pause");
    return 0;
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值