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. connectedSignal 简单使用

    import java.util.concurrent.CountDownLatch; public class CountDown { private static CountDownLatch c ...

  2. NOI 97 (Vijos 1464)积木游戏(DP)

    很普通的DP,设dp[i][j][k]为第i块积木放在第j堆且摆放状态为k的最高高度.方程很容易推出. # include <cstdio> # include <cstring&g ...

  3. OracleHelp以及其简单应用

    我自己写的简单的OracleHelp <?xml version="1.0" encoding="utf-8" ?> <configurati ...

  4. [HDU4532]湫秋系列故事——安排座位

    题面在这里 description 有\(n\)种颜色的小球,每种颜色的小球有\(a_i\)个: 要把它们摆成一排,求相邻小球颜色不相同的摆放方案数. 任意两个合理的安排方法,只要有一个位置的同学不同 ...

  5. [洛谷P3975][TJOI2015]弦论

    题目大意:求一个字符串的第$k$大字串,$t$表示长得一样位置不同的字串是否算多个 题解:$SAM$,先求出每个位置可以到达多少个字串($Right$数组),然后在转移图上$DP$,若$t=1$,初始 ...

  6. [洛谷P2106]Sam数

    题目大意:问长度为$n$的$Sam$数有几个,$Sam$数的定义为没有前导零,相邻两个数字之差绝对值小于等于$2$的数 题解:发现转移方程一定,可以矩阵快速幂. 卡点:没有特判$n=1$的情况 C++ ...

  7. 容器化RDS|计算存储分离 or 本地存储?

    随着交流机会的增多(集中在金融行业,规模都在各自领域数一数二),发现大家对 Docker + Kubernetes 的接受程度超乎想象, 并极有兴趣将这套架构应用到 RDS 领域.数据库服务的需求可以 ...

  8. 洛谷4578 & LOJ2520:[FJOI2018]所罗门王的宝藏——题解

    https://www.luogu.org/problemnew/show/P4578 https://loj.ac/problem/2520 有点水的. 先转换成图论模型,即每个绿宝石,横坐标向纵坐 ...

  9. sd卡的访问

    一般再访问sd卡前都要获取sd卡的路径,以防止不同的厂商有不同的路径配置.Android提供了Environment类来获取系统当前sd卡路径. Log.d(TAG, Environment.getE ...

  10. X day2

    题目 官方题解 T1: 我们可以把问题化简为$a\times b \times c \leq n $中的有序$(a,b,c)$有多少组.分三种情况考虑 当$a=b=c$时,答案十分好统计 当$a< ...