C# 判断一个单链表是否有环及环长和环的入口点
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# 判断一个单链表是否有环及环长和环的入口点的更多相关文章
- 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. ...
- C语言一个单链表的实现
-- 所谓链表记住一句即可:地址不连续,大家只是握个手而已: list0.c #include<stdio.h> #include<malloc.h> typedef int ...
- java单链表的实现自己动手写一个单链表
单链表:单链表是一种链式存取的数据结构,用一组地址任意的存储单元存放线性表中的数据元素.链表中的数据是以结点来表示的,每个结点的构成:元素(数据元素的映象) + 指针(指示后继元素存储位置),元素就是 ...
- c语言,递归翻转一个单链表,c实现单链表
目的:主要是练习c里面单链表的实现,递归思想复习; #include <stdlib.h> #include <stdio.h> typedef struct _Node{// ...
- [二叉树算法]让树所有叶子节点连成一个单链表,让rchild作为 next指针
//让树所有叶子节点连成一个单链表,让rchild作为 next指针 LNode *head=null,*pre=null;//全局变量 LNode *InOrder(BTNode *T){ if(T ...
- java判断一个单向链表是否有环路
今天刷LeetCode刷到一道这样的题,详情参见(https://leetcode-cn.com/problems/linked-list-cycle/) ADT: class ListNode { ...
- php实现一个单链表
单链表,节点只有一个指针域的链表.节点包括数据域和指针域. 因此用面向对象的思维,节点类的属性就有两个:一个data(表示存储的数据),一个指针next(链表中指向下一个节点). 链表一个很重要的特性 ...
- 如何判断一个单向链表是否为回文链表(Palindrome Linked List)
题目:给定一个单向链表,判断它是不是回文链表(即从前往后读和从后往前读是一样的).原题见下图,还要求了O(n)的时间复杂度O(1)的空间复杂度. 我的思考: 1,一看到这个题目,大脑马上想到的解决方案 ...
- 008实现一个算法从一个单链表中返回倒数第n个元素(keep it up)
我们维护两个指针, 它们之间的距离为n. 然后.我将这两个指针同步地在这个单链表上移动,保持它们的距离 为n不变. 那么, 当第二个指针指到空时.第一个指针即为所求. #include <ios ...
随机推荐
- poj1065-Wooden Sticks
题目 有很多小木棍需要机器处理.每个小木棍有重量和长度两个属性.不断把小木棍放入机器中,如果小木棍\(a\)放完后放入小木棍\(b\),那么如果\(a.weight<=b.weight\ and ...
- Shel脚本学习—反引号、单引号、双引号区别与联系
反引号 反引号位 (`) 位于键盘的Tab键的上方.1键的左方.注意与单引号(')位于Enter键的左方的区别. 在Linux中起着命令替换的作用.命令替换是指shell能够将一个命令的标准输出插在一 ...
- 海盗船长小米首页小船来回摆动CSS3.0效果
海盗船长小米首页小船来回摆动CSS3.0效果,偶然之间看到的,就写了一个. <!DOCTYPE html> <html lang="en"> <hea ...
- BZOJ4850/BZOJ2216 JSOI2016灯塔/Poi2011Lightning Conductor(决策单调性)
即对每个i最大化hj-hi+sqrt(|i-j|).先把绝对值去掉,正反各做一次即可.注意到当x>y时,sqrt(x+1)-sqrt(x)<sqrt(y+1)-sqrt(y),所以若对于i ...
- NAT穿透(UDP打洞)
1.NAT(Network Address Translator)介绍 NAT有两大类,基本NAT和NAPT. 1.1.基本NAT 静态NAT:一个公网IP对应一个内部IP,一对一转换 动态NAT:N ...
- C# 代码操作XML(增、删、改)
目录: 1.创建XML 1)创建普通XML 2)创建带属性的XML 2.追加XML 3.读取XML 1)读取普通XML 2)读取带属性的XML 4.修改属性的值 5.删除XML节点 作为一个小型的数 ...
- Elasticsearch 插件head和kibana
本次安装在win7下,linux操作差不多. Elasticsearch的版本是6.5.1 一.前置条件 1.安装nodejs,如果已经安装了,检查一下版本,最好大于6以上,不然后面会失败,官网上已经 ...
- HDOJ.1070 Milk(贪心)
Milk 点我挑战题目 题意分析 每组测试数据给出一系列牛奶商品,分别是牛奶的品牌,价格,以及体积.在读取数据的时候,体积在200以下的牛奶直接忽略掉.并且每天要喝200ML的牛奶.但是无论牛奶体积有 ...
- HDU 5646
DZY Loves Partition Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Ot ...
- UVA10600:ACM Contest and Blackout(次小生成树)
ACM Contest and Blackout 题目链接:https://vjudge.net/problem/UVA-10600 Description: In order to prepare ...