博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
面试题_单链表环的问题
阅读量:7287 次
发布时间:2019-06-30

本文共 1817 字,大约阅读时间需要 6 分钟。

问题:有一个单链表,其中可能有一个环,也就是某个节点的next指向的是链表中在它之前的节点,这样的链表的尾部形成一环。

1、如何判断一个链表是否存在环?

2、如果链表存在环,如何找到环的入口点?

问题1分析:设置两个指针fast和slow,初始值都指向头指针,slow每次前进一步,fast每次前进两步。如果存在环,则fast必先进入环,而slow后进入环,两个指针必定相遇,当然,fast先到达尾部为NULL,则为无环链表。

证明:两个指针fast和slow,fast一次递增两步,slow一次递增一步。如果有环的话两者必然重合,反之亦然。因为fast每次走2步,而slow每次走一步,所以它们之间的差距是一步一步缩小的。当slow进入环入口点后,fast和slow之间的差距将会一步步缩小,如4,3,2,1,0。到0的时候就重合了。根据此方式,可以证明,fast每次走三步以上,并不总能加快检测速度,反而有可能判别不出环。

问题2分析:如果fast和slow相遇,那么在相遇时,slow肯定没有遍历完链表,而fast已经在环内循环了n圈(n>=1)。

假设slow走了s步,则fast走了2s步(fast的步数还等于s加上在环上多转的n圈),设环长为r,则:

2s=s+nr

s=nr

设整个链表长L,入口环与相遇点距离为x,起点到环入口点的距离为a,则

a+x=s=nr

a+x=(n-1)r+r=(n-1)r+L-a

a=(n-1)r+(L-a-x)

(L-a-x)为相遇点到环入口点的距离。由此可知,从链表头到环入口点等于(n-1)循环内环+相遇点到环入口点。于是可以从链表头和相遇点分别设一个指针,每次各走一步,两个指针必定相遇,且相遇第一点为环入口点。

#include
<
iostream
>
using
namespace
std;
struct
Node
{
Node
*
next;
int
value;
Node(
int
v)
{
value
=
v;
next
=
NULL;
}
};
Node
*
isExistLoop(Node
*
head)
{
//
slow一次走一步,fast一次走两步
Node
*
slow
=
head,
*
fast
=
head;
while
(fast
!=
NULL
&&
fast
->
next
!=
NULL)
{
slow
=
slow
->
next;
fast
=
fast
->
next
->
next;
if
(slow
==
fast)
return
slow;
}
return
NULL;
}
Node
*
findLoopNode(Node
*
head)
{
Node
*
second
=
isExistLoop(head);
second = second->next;
if
(second
==
NULL)
return
NULL;
Node
*
first
=
head;
while
(second
!=
first)
{
second
=
second
->
next;
first
=
first
->
next;
}
return
first;
}
int
main()
{
const
int
LENGTH
=
20
;
Node
*
nodelist[LENGTH];
nodelist[
0
]
=
new
Node(
0
);
Node
*
head
=
nodelist[
0
];
Node
*
pre
=
head;
for
(
int
i
=
1
;i
<
LENGTH;i
++
)
{
nodelist[i]
=
new
Node(i);
pre
->
next
=
nodelist[i];
pre
=
nodelist[i];
}
pre
->
next
=
nodelist[
14
];
if
(isExistLoop(head))
{
cout
<<
"
存在环
"
<<
endl;
}
else
cout
<<
"
不存在环
"
<<
endl;
cout
<<
findLoopNode(head)
->
value
<<
endl;
for
(
int
j
=
0
;j
<
LENGTH;j
++
)
{
delete nodelist[j];
}
return
0
;
}

转载地址:http://wypjm.baihongyu.com/

你可能感兴趣的文章
Mail服务器架设
查看>>
C++中关于指针作为参数传递的问题
查看>>
大清单报表应当怎么做?
查看>>
Spring AOP 实现方法日志记录以及执行时间打印
查看>>
Linux中 tail -f;tail -F;tailf的区别
查看>>
Linux下的数据备份工具rsync
查看>>
支付宝小程序注意事项
查看>>
ArrayList
查看>>
【小松教你手游开发】【unity实用技能】List列表排序
查看>>
日常工作之Zabbix源码编译,兼容mysql5.6
查看>>
Zabbix分布式监控
查看>>
中兴智能视觉大数据报道:人工智能相当火爆,或将下一个风口
查看>>
OCP 12c最新考试原题及答案(071-3)
查看>>
xdebug+phpstorm(windows)
查看>>
Spring Boot整合Hibernate操作
查看>>
阿里云移动端播放器高级功能---直播时移
查看>>
主动式部署陷阱
查看>>
webx2.0-RundataService学习总结
查看>>
SpringMVC的拦截器(Interceptor)和过滤器(Filter)的区别与联系
查看>>
云计算培训论云计算下的网络安全及措施
查看>>