1.为什么写这个随笔?

前几天参加一个电面,被问到这个问题,想总结一下。

2.为什么标题强调C#?

想在网上看看代码,却没找到C#版的,于是自己用C#实现一下。

一、解决问题的思路

1.一种比较耗空间的做法是,从头开始遍历链表,把每次访问到的结点存入一个集合(hashset)或字典(dictionary),如果发现某个结点已经被访问过了,就表示这个链表存在环,并且这个结点就是环的入口点。

空间复杂度为O(n),时间复杂度为O(n)

2.追赶法:使用两个slow, fast指针从头开始扫描链表。指针slow 每次走1步,指针fast每次走2步。如果存在环,则指针slow、fast会相遇;如果不存在环,指针fast遇到NULL退出。

空间复杂度为O(1),时间复杂度为O(n)

仅仅考虑代码实现方面第一种方法相对简单,所以下面用第二种方法来实现。

二、解析(追击相遇)

给出一个存在环的单链表:1,2,3,4,5,3,4,5...

用图表示出来:

然后按照追赶法的定义一步一步走:

从上图可以看出第四次和第七次快慢指针在节点4处相遇,7-4=3,正好是环的长度;

求出环的长度后,我们便可以求出入口点:

链表总长=5;

头结点到入口点的距离=链表总长-环长;即=5-3=2;

然后从头结点开始向下遍历,得到入口点3;

三、代码

1.单链表节点

 //单链表节点
class LinkNode<T>
{
public LinkNode<T> Next
{ get; set; }
public T Data
{ get; set; }
public LinkNode()
{
Data = default(T);
Next = null;
}
public LinkNode(T val)
{
Data = val;
Next = null;
}
public LinkNode(T val,LinkNode<T> node)
{
Data = val;
Next = node;
}
}

2.单链表

     class DLinkedList<T>
{
public LinkNode<T> Head
{ get; set; }
public int Length
{ get; set; }
public DLinkedList()
{
Length = ;
Head = null;
}
public void Add(LinkNode<T> node)//插入节点
{
if (IsEmpty())
{
Head = node;
Length++;
return;
}
else
{
LinkNode<T> currentNode = Head;
while (currentNode.Next != null)
{
currentNode = currentNode.Next;
}
currentNode.Next = node;
Length++;
}
}
public void Display()//显示链表
{
LinkNode<T> currentNode = Head;
while (currentNode != null)
{
Console.WriteLine(currentNode.Data);
currentNode = currentNode.Next;
}
}
public int GetLength()//获取链表长度
{
return Length;
}
public bool IsEmpty()//判空
{
return Head == null ? true : false;
}
public bool HasCircle()//判断是否有环
{
LinkNode<T> slowNode = Head;
LinkNode<T> fastNode = Head;//定义快慢节点,开始指向头结点
bool result = false;
int count = ;
int step = ;
while (slowNode.Next != null && fastNode.Next.Next != null)
{
try
{
slowNode = slowNode.Next;//慢节点指向下一个
fastNode = fastNode.Next.Next;//快节点指向下一个节点的下一个节点
}
catch (NullReferenceException)
{
result = false;
break;
}
if (slowNode == fastNode && slowNode != Head && slowNode != null)
{
result = true;
Console.WriteLine($"The currentNode's Data is {slowNode.Data}");
count++;
}
if (count == )//第一次相遇
step++;//计步,获取环长
if (count == )//第二次相遇
{
Console.WriteLine($"Circle's length is {step}");
break;
}
}
GetPoint(step);
return result;
}
public LinkNode<T> GetPoint(int circleLength)//获取相交点
{
int lineLength = Length -circleLength;
int num = ;
LinkNode<T> currentNode = Head;
while(currentNode.Next!=null)
{
currentNode = currentNode.Next;
num++;
if(num==lineLength)
{
break;
}
}
Console.WriteLine($"The meet node's Data is {currentNode.Data}");
return currentNode;
}
}

3.测试

 class Program
{
static void Main(string[] args)
{
DLinkedList<int> list = new DLinkedList<int>();
LinkNode<int> tmp=null;
for(int i =;i<=;i++)
{
LinkNode<int> node = new LinkNode<int>(i);
if (i == )
tmp = node;
list.Add(node);
}
list.Add(tmp);
Console.WriteLine(list.HasCircle());
Console.ReadKey();
}
}

测试结果如图:

C# 判断一个单链表是否有环及环长和环的入口点的更多相关文章

  1. LeetCode 笔记系列六 Reverse Nodes in k-Group [学习如何逆转一个单链表]

    题目:Given a linked list, reverse the nodes of a linked list k at a time and return its modified list. ...

  2. C语言一个单链表的实现

    -- 所谓链表记住一句即可:地址不连续,大家只是握个手而已: list0.c #include<stdio.h> #include<malloc.h> typedef int ...

  3. java单链表的实现自己动手写一个单链表

    单链表:单链表是一种链式存取的数据结构,用一组地址任意的存储单元存放线性表中的数据元素.链表中的数据是以结点来表示的,每个结点的构成:元素(数据元素的映象) + 指针(指示后继元素存储位置),元素就是 ...

  4. c语言,递归翻转一个单链表,c实现单链表

    目的:主要是练习c里面单链表的实现,递归思想复习; #include <stdlib.h> #include <stdio.h> typedef struct _Node{// ...

  5. [二叉树算法]让树所有叶子节点连成一个单链表,让rchild作为 next指针

    //让树所有叶子节点连成一个单链表,让rchild作为 next指针 LNode *head=null,*pre=null;//全局变量 LNode *InOrder(BTNode *T){ if(T ...

  6. java判断一个单向链表是否有环路

    今天刷LeetCode刷到一道这样的题,详情参见(https://leetcode-cn.com/problems/linked-list-cycle/) ADT: class ListNode { ...

  7. php实现一个单链表

    单链表,节点只有一个指针域的链表.节点包括数据域和指针域. 因此用面向对象的思维,节点类的属性就有两个:一个data(表示存储的数据),一个指针next(链表中指向下一个节点). 链表一个很重要的特性 ...

  8. 如何判断一个单向链表是否为回文链表(Palindrome Linked List)

    题目:给定一个单向链表,判断它是不是回文链表(即从前往后读和从后往前读是一样的).原题见下图,还要求了O(n)的时间复杂度O(1)的空间复杂度. 我的思考: 1,一看到这个题目,大脑马上想到的解决方案 ...

  9. 008实现一个算法从一个单链表中返回倒数第n个元素(keep it up)

    我们维护两个指针, 它们之间的距离为n. 然后.我将这两个指针同步地在这个单链表上移动,保持它们的距离 为n不变. 那么, 当第二个指针指到空时.第一个指针即为所求. #include <ios ...

随机推荐

  1. BZOJ 1046 上升序列(LIS变形)

    要保证长度为L的序列下标字典序最小,当然要尽量选前面的数. 如何判断前面的数是否满足条件?,只需要知道这个数开头的递增序列的最长长度是多少,如果不小于L,那么必然可以加入这个数.还需判断一下它是否大于 ...

  2. 运动员最佳匹配问题 KM算法:带权二分图匹配

    题面: 羽毛球队有男女运动员各n人.给定2 个n×n矩阵P和Q.P[i][j]是男运动员i和女运动员j配对组成混合双打的男运动员竞赛优势:Q[i][j]是女运动员i和男运动员j配合的女运动员竞赛优势. ...

  3. BZOJ3172 [Tjoi2013]单词 【AC自动机】

    3172: [Tjoi2013]单词 Time Limit: 10 Sec  Memory Limit: 512 MB Submit: 4293  Solved: 2083 [Submit][Stat ...

  4. [Ahoi2005]COMMON 约数研究 【欧拉线性筛的应用】

    1968: [Ahoi2005]COMMON 约数研究 Time Limit: 1 Sec  Memory Limit: 64 MB Submit: 2939  Solved: 2169 [Submi ...

  5. [学习笔记]NTT——快速数论变换

    先要学会FFT[学习笔记]FFT——快速傅里叶变换 一.简介 FFT会爆精度.而且浮点数相乘常数比取模还大. 然后NTT横空出世了 虽然单位根是个好东西.但是,我们还有更好的东西 我们先选择一个模数, ...

  6. # Codeforces Round #529(Div.3)个人题解

    Codeforces Round #529(Div.3)个人题解 前言: 闲来无事补了前天的cf,想着最近刷题有点点怠惰,就直接一场cf一场cf的刷算了,以后的题解也都会以每场的形式写出来 A. Re ...

  7. bzoj 2086 [Poi2010]Blocks 单调栈

    [Poi2010]Blocks Time Limit: 20 Sec  Memory Limit: 259 MBSubmit: 788  Solved: 356[Submit][Status][Dis ...

  8. arm-linux-gcc等交叉编译工具的安装

    1.软件安装 步骤1:打开虚拟机,在/usr/local/下创建/usr/local/arm文件夹(一般用户自定义程序放到这里) 步骤2:先将安装包从Windows中弄到linux中去.可以用共享文件 ...

  9. vue-cli中引入jquery的方法

    vue-cli中引入jquery的方法 以前写vue项目都没有引入过jquery,今天群里面的一位小伙伴问了我这个问题,我就自己捣鼓了一下,方法如下: 我们先进入webpack.base.conf.j ...

  10. [洛谷P1404] 平均数

    洛谷题目链接:平均数 题目描述 给一个长度为n的数列,我们需要找出该数列的一个子串,使得子串平均数最大化,并且子串长度>=m. 输入输出格式 输入格式: N+1行, 第一行两个整数n和m 接下来 ...