问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

判断单链表中是否有环,找到环的入口节点

发布网友 发布时间:2022-04-14 20:53

我来回答

2个回答

懂视网 时间:2022-04-15 01:14

给定一个有环链表,实现以算法返回环路的开头结点。 有环链表的定义 在链表中某个节点的next元素指向它前面出现过的节点,则表明该链表存在环路。 示例 输入:A-B-C-D-E-C(C节点出现两次) 输出:C 分析 : 1,快慢指针法判断链表是否有环 fast每次前移两步,

给定一个有环链表,实现以算法返回环路的开头结点。

有环链表的定义

在链表中某个节点的next元素指向它前面出现过的节点,则表明该链表存在环路。

示例

输入:A->B->C->D->E->C(C节点出现两次)

输出:C

分析:

1,快慢指针法判断链表是否有环

fast每次前移两步,slow每次前移一步,两指针若能相遇,则有环,否则没有环。

2,假设链表头到环头移动k步,slow指向环头的时候,fast移动了2*k步,此时两者相距k步,也可以认为快指针再过m*size-k步之后追上慢指针。当两者相遇的时候,则慢指针距离环头还有k步。因为此时不知道k的具体大小,但是知道k是链表头到环头的步数,让fast指向链表头,之后快慢指针每次往后移动一步,两者相遇的地方就是环头。

package test;

public class FindLoopStart {
	public Node findLoopStart(Node head){
		Node fast = head;
		Node slow = head;
		while(fast!=null || fast.next!=null){
			fast = fast.next.next;
			slow = slow.next;
			if(fast == slow)
				break;
		}
		//没有环则返回null
		if(fast==null || fast.next==null)
			return null;
		//相遇之后,slow节点再走k步达到环开头
		//此时,并不知道k的具体值,但是知道k是从链表开头到环头的步数
		//于是,让fast指向链表头,每次往后移一步,则再次相遇的时候,走的步数就是k
		//则相遇地点就是环的开头
		fast = head;
		while(fast != slow){
			fast = fast.next;
			slow = slow.next;
		}
		return slow;
	}
}

热心网友 时间:2022-04-14 22:22

1.判断链表是否有环
设置两个指针slow和fast,初始值均指向链表头,slow每次向前走一步,而fast每次向前走两步.
如果链表有环,则fast先进入环里,而slow后进入环里,两个指针在环中必定相遇.
如果slow与fast没有相遇,fast遍历到链表的尾部,则表示链表没有环.

2.链表有环,确定环的入口点
设置slow指针指向链表头,fast指向相遇点,每次两个指针都是只走一步,两个指针必定相遇,
则相遇第一点为环入口点.

( 为什么 两个指针相遇的地方就是环入口点?
  先从"判断链表是否有环"的那种情况说起.
  假设从链表头到环入口点的距离是x, 在环里两个指针相遇的那点与环入口点的距离是w,
  fast指针在环里走了n圈才与slow相遇,环的长度是L,那么,
  slow指针在相遇时走过的距离是 x + w
  fast指针走过的距离是 x + w + n*L
  因为slow每次向前走一步,而fast每次向前走两步,有如下等式:
  2 * (x + w) = x + w + n*L
  化简得到: x + w = n*L
  也就是 x = n*L - w  [等式1]
  假设相遇的时候,fast在环内只走了一圈,n=1,代入[等式1],得到 x = L - w
  现在,slow从链表头开始走,fast继续从相遇点开始走,两个指针都只走一步,
  那么,slow走了x,而fast走了(L - w),必定相遇,而且刚好在环入口点.
  假设相遇的时候,fast在环内走了超过一圈,那么[等式1]可以写为:
  x = (n-1)*L + (L- w)
  那么,slow走了x,而fast走了(n-1)圈后,再走(L - w),必定相遇,而且刚好在环入口点. )

3.计算环长
在环的入口点设置一个指针和一个计数器,让这个指针在环里面走,每走一步,计数器就加1,
当这个指针回到环的入口点的时候,计数器的值就是环长.

测试结果:

链表1:
10 20 30 40 50 20 30 40 50 20 30 40 50 20 30 40 50 20 30 40 ......
有环, 环入口点是: 20
环长是: 4

链表2:
1 2 3 4 5
链表没有环


//C语言测试程序
#include <stdio.h>
#include <stdlib.h>

typedef struct Node
{
    int data;
    struct Node *next;
}Node,*LinkList;

//创建链表(有"环")
LinkList CreateLinkWithLoop()
{
    LinkList head; //链表头
    Node *newNode; //新结点
    Node *ptr;     //指向当前结点
    Node *pEntry;  //指向"环"的入口

    newNode=(Node *)malloc(sizeof(Node));
    newNode->data=10;
    newNode->next=NULL;
    head=newNode;       //设置链表头
    ptr=newNode;

    newNode=(Node *)malloc(sizeof(Node));
    newNode->data=20;
    newNode->next=NULL;
    ptr->next=newNode;
    ptr=newNode;
    pEntry=newNode;  //指向"环"的入口

    newNode=(Node *)malloc(sizeof(Node));
    newNode->data=30;
    newNode->next=NULL;
    ptr->next=newNode;
    ptr=newNode;

    newNode=(Node *)malloc(sizeof(Node));
    newNode->data=40;
    newNode->next=NULL;
    ptr->next=newNode;
    ptr=newNode;

    newNode=(Node *)malloc(sizeof(Node));
    newNode->data=50;
    newNode->next=pEntry; //产生"环"
    ptr->next=newNode;
    ptr=newNode;

    return head;
}

//创建链表(没有"环")
LinkList CreateLink()
{
    LinkList head; //链表头
    Node *newNode; //新结点
    Node *ptr;     //指向当前结点
    int i;

    newNode=(Node *)malloc(sizeof(Node));
    newNode->data=1;
    newNode->next=NULL;
    head=newNode;       //设置链表头
    ptr=newNode;

    for(i=2;i<=5;i++)
    {
        newNode=(Node *)malloc(sizeof(Node));
        newNode->data=i;
        newNode->next=NULL;
        ptr->next=newNode;
        ptr=newNode;
    }

    return head;
}

//打印链表
void PrintLink(LinkList head)
{
    LinkList ptr;
    int nCount=0;

    ptr=head;
    while(ptr!=NULL)
    {
        printf("%d ",ptr->data);
        ptr=ptr->next;
        nCount++;
        if(nCount>=20)
        {
            printf("......");
            break;
        }
    }
    printf("\n");
}

//判断链表是否有"环",确定"环"的入口点
LinkList CheckLinkLoop(LinkList head)
{
    LinkList fast;
    LinkList slow;
    int isLoop=0;

    fast=head;
    slow=head;

    while(fast != NULL && fast->next != NULL)
    {
        //fast每次走两步,slow每次走一步
        //当两个指针相等时,表示链表有"环"
        slow=slow->next;
        fast=fast->next->next;
        if(fast == slow)
        {
            isLoop=1; //1=有环, 0=没有环
            break;
        }
    }
    if(isLoop==1) //有"环"时
    {
        //slow指向链表头,fast指向相遇点,两个指针每次都只走一步
        //当两个指针第一次相等时,就是环入口点
        slow=head;
        while(slow != fast)
        {
            slow=slow->next;
            fast=fast->next;
        }
        return slow;
    }
    else //没有"环"
    {
        return NULL;
    }
}

//计算环长
int GetLoopSize(LinkList entryNode)
{
    LinkList ptr;
    int nCount=0;

    ptr=entryNode->next;
    nCount++;

    while(ptr!=entryNode)
    {
        nCount++;
        ptr=ptr->next;
    }

    return nCount;
}

int main()
{
    LinkList head_1;
    LinkList head_2;
    LinkList ret_1;
    LinkList ret_2;
    int loopSize_1;
    int loopSize_2;

    head_1=CreateLinkWithLoop(); //创建链表(有"环")

    printf("链表1:\n");
    PrintLink(head_1); //打印链表

    ret_1=CheckLinkLoop(head_1);
    if(ret_1!=NULL)
    {
        printf("有环, 环入口点是: %d\n",ret_1->data);
        loopSize_1=GetLoopSize(ret_1);
        printf("环长是: %d\n",loopSize_1);
    }
    else
    {
        printf("链表没有环\n");
    }

    head_2=CreateLink(); //创建链表(没有"环")

    printf("\n链表2:\n");
    PrintLink(head_2); //打印链表

    ret_2=CheckLinkLoop(head_2);
    if(ret_2 != NULL)
    {
        printf("有环, 环入口点是: %d\n",ret_2->data);
        loopSize_2=GetLoopSize(ret_2);
        printf("环长是: %d\n",loopSize_2);
    }
    else
    {
        printf("链表没有环\n");
    }

    return 0;
}

声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
可以用电高压锅做蛋糕吗 蛋糕机选哪家实惠? 京东闪付开通后无法添加到applepay怎么办 二年级数学说课稿范文 苹果手机电充到80就不充了怎么回事 上有八,下有八中间有个十字花打一字 ...排名22000.能否上到广工的机械制造和自动化(卓越工程师班)_百度知 ... 把内存由DDR2升级到DDR3,是不是要设置什么东东啊。 怎样吧DDR2的内存条改成DDR3 ...的内存条是DDR2的,我想换DDR3的可以吗?该怎么换?还有该注意什么... word文档中,左对齐找不到了 整个新乡市有哪些上市公司? be ready for的意思 Word中为什么左右对齐在标题栏上点不了!求解呀!! be ready for sth,get ready for sth be ready to do sth,get ready to do sth, prepare for st word中标题都已经用样式设置,但生成目录后标题一没左对齐,怎么办? word目录标题左边对不齐 河南所有上市企业的准确名单(上市公司名称 地址 邮政编码 股票代码) 河南都有哪些上市公司? be ready +什么介词,是to还是for be ready for 与be ready to do的意思有区别吗?如果有,有什么区别? be ready to do 和 be ready for doing 区别 有be ready for sth 么,谢谢 初二英语,be ready to do sth 和be ready for sth 的意思和区别~ 晚上睡觉一直做梦,易醒,多翻动,浑身疼是怎么了? be ready for是什么意思 bereadyfor的英汉互译 be ready for= be ready for后面能不能加形容词 be ready for 后接动名词吗 瞬间爆炸粤语怎么发音 粤语怎么说“哄人”? 南宁话怎么说,谁说几句搞笑的来听听 唱歌不会跟拍怎么办 不会剪辑、拍摄怎么办? 男朋友旅行时不会拍照怎么办 哪年再闰十月 那年润十月? 闰十月的简介 这个世纪有哪几个年份会有闰十月出现?? 1991年好像闰十月,万年历怎么没有 给定单链表,检测是否有环.如果有环,则求出进入环的第一个节点 SK-Ⅱ,是什么意思? 苹果手机迅雷解压文件在哪里? 电脑解压完文件怎么导入苹果手机 收到承兑汇票,但金额大于货款要还回去会计分录怎么做 肺部小结节怎么办 体检发现肺部小结节,你该怎么办 咸宁市中高五级教师,工龄41年,教龄37年,薪级45级,2022年退休,退休工资多少? 我是事业单位职工,今年退休,工龄41年,中级职称,请问退休能拿到多少退休金_百度问一问