判断链表内是否有环以及环的入口节点(C语言实现) 附详细的代码注释

#include <stdio.h>
#include <stdlib.h>
/*找到环的入口节点的核心思路:
步骤:
1)、确认链表中有环
2)、计算环的长度
3)、获得环的入口
在获得环入口的时候,有如下公式:
(式子说明:快指针移动的距离:s  慢指针移动的距离:m
起点到入口点的距离:d  入口点到相遇点的距离:p   相遇点到入口点的距离:q
快指针在环内移动的圈数:n )
s = 2m;          (1)
环长g:p+q
s = d+(p+q)*n+p  (2)
m = d+p          (3)
将(3)带入(1),得到:
s = 2*(d+p)      (4)
将(4)带入(2),得到:
2*(d+p) = d+(p+q)*n+p
化简:
d + p = (p+q)*n
构造一下:
d+(p+q)-p = (p+q)*n
d = p+(p+q)*(n-1)
也就是说:在矢量图上,d距离入口点和p距离入口点的距离是相等的
*/

/*定义一个节点结构体*/
typedef struct node{
    int data;
    struct node *next;
}Node;
/*遍历链表*/
void travelList(Node *head)
{
    head = head->next;
    while(head)
    {
        printf("%d  ",head->data);
        head = head->next;
    }
}
/*创建链表*/
Node * createList(int data)
{
    Node *newList = (Node*)malloc(sizeof(Node));
    /*判断分配内存是否成功*/
    if(newList == NULL)  printf("create fail \n");
    newList->data = data;
    newList->next = NULL;
    return newList;
}

/*连接函数  用来创建循环链表(这个创建方式和之前的不一样)*/
void connectList(Node *node1,Node *node2)
{
    node1->next = node2;
}

/*判断是否会相遇(是否有环)   有环,返回相遇的节点;没环,返回NULL*/
Node * findMeetNode(Node *head)
{
    /*定义快慢指针*/
    Node *sNode =NULL,*fNode=NULL;
    /*指针定义*/
    sNode = head->next;
    fNode = sNode->next;

    while(fNode != NULL)
    {
        /*相遇了*/
        if(fNode == sNode)
        {
            return sNode;
            break;
        }
        sNode = sNode->next;
        fNode = fNode->next;
        /*快指针移动的快。先移动一次,用if判断一下*/
        if(fNode == NULL) return NULL;
        /*快指针的步长是2,所以移两次*/
        /*这次移动以后,用外层while判断一次*/
        fNode = fNode->next;
    }
    return NULL;
}
/*判断环的入口*/
Node *EntryNode(Node *head)
{
    /*初始值为快慢指针 相遇的节点*/
    Node *meetNode  = findMeetNode(head);
    Node *headNode  = head;
    while(meetNode != headNode)
    {
        meetNode = meetNode->next;
        headNode = headNode->next;
    }
    return headNode;
}


int main(void)
{
    Node* pNode1 = createList(1);
    Node* pNode2 = createList(20);
    Node* pNode3 = createList(3);
    Node* pNode4 = createList(41);
    Node* pNode5 = createList(5);
    Node* pNode6 = createList(6);

    connectList(pNode1, pNode2);
    connectList(pNode2, pNode3);
    connectList(pNode3, pNode4);
    connectList(pNode4, pNode5);
    connectList(pNode5, pNode6);
    connectList(pNode6, pNode2);

    if(EntryNode(pNode1)!=NULL)
          printf("%d",EntryNode(pNode1)->data);
    else
          printf("Error");
}




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

One Piece&

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值