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. BZOJ5466 NOIP2018保卫王国(倍增+树形dp)

    暴力dp非常显然,设f[i][0/1]表示i号点不选/选时i子树内的答案,则f[i][0]=Σf[son][1],f[i][1]=a[i]+Σmin(f[son][0],f[son][1]). 注意到 ...

  2. BZOJ4028 HEOI2015公约数数列(分块)

    前缀gcd的变化次数是log的,考虑对每一种gcd查询,问题变为查询一段区间是否存在异或前缀和=x/gcd. 无修改的话显然可以可持久化trie,但这玩意实在没法支持修改.于是考虑分块. 对于每一块将 ...

  3. 【题解】JXOI2017颜色

    一眼线段树...显然,我们可以考虑最后所留下的区间,那显然这个区间中应当不能存在任何与区间外相同的颜色.这里的转化也是很常用的,我们用 \(nxt[i]\) 表示与 \(i\) 颜色相同的下一个位置在 ...

  4. [SDOI2014]数表 莫比乌斯反演

    ---题面--- 题解: 设$f(d)$表示数$d$的约数和,那么$(i, j)$中的数为$f(gcd(i, j))$,那么有2种枚举方法.1,枚举每一格看对应的$f(d)$是几.$$ans = \s ...

  5. BZOJ4311:向量——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=4311 你要维护一个向量集合,支持以下操作: 1.插入一个向量(x,y) 2.删除插入的第i个向量 ...

  6. 几个与特殊字符处理有关的PHP函数(过滤html js 标签)

    函数名 释义 介绍 htmlspecialchars 将与.单双引号.大于和小于号化成HTML格式 &转成&"转成"' 转成'<转成<>转成> ...

  7. 在 C Level 用 dlopen 使用 第三方的 Shared Library (.so)

    http://falldog7.blogspot.com/2013/10/android-c-level-dlopen-shared-library-so.html 在 Android 裡,撰寫 JN ...

  8. Train-net流程

  9. STL之三:deque用法详解

    转载于:http://blog.csdn.net/longshengguoji/article/details/8519812 deque函数: deque容器为一个给定类型的元素进行线性处理,像向量 ...

  10. 求前n项正整数的倒数和

    求前n项正整数的倒数和 前n项正整数的和是一个发散的序列,学过高等数学的这个都知道.所以它没有一个精确的公式,但是近似的公式是有的: 1 + 1/2 + 1/3 + …… + 1/n ≍ ln n + ...