链表环问题研究

有一个单链表,其中可能有一个环,也就是某个节点的next指向的是链表中在它之前的节点,这样在链表的尾部形成一环。如下图所示
这里写图片描述
下面分析如何检测出来
首先想到的是是否可以将走过的路径记录下来,每次都需要检测这个是否遍历过,
当然这里考虑链表的长度比较短
首先模拟一个链表环,然后利用vector保存每个链表节点的地址,每次都进行搜索;

typedef struct node
{
 int data;
 struct node* next;
}LIST;

然后模拟一个简单链表环

LIST* creat()
{
 int i=0;
 LIST* h;
 LIST* n;
 LIST* nn;
 LIST* r;
 h=n=nn=r=NULL;

 h=(LIST*)malloc(sizeof(LIST));
 assert(h!=NULL);
 h->data=1;
 n=nn=h;

 n=(LIST*)malloc(sizeof(LIST));
 assert(n!=NULL);
 n->data=2;
 nn->next=n;
 r=n;

 nn=(LIST*)malloc(sizeof(LIST));
 assert(nn!=NULL);
 nn->data=3;
 n->next=nn;

 n=(LIST*)malloc(sizeof(LIST));
 assert(n!=NULL);
 n->data=4;
 nn->next=n;

 n->next=r;

 return h;
}

全局区设置

vector <LIST*> tab;

用于保存遍历过的链表节点地址。

bool search(LIST* h)
{   int i=0;
 for(i=0;i<tab.size();++i)
  if(tab[i]==h)return true;
 return false;
}
bool check(LIST* h)
{

 assert(h!=NULL);
 while(h!=NULL)
 {
  if(search(h))
   return true;
  else
   tab.push_back(h);
  h=h->next;
 }
 return false;
}

但是这种最直接方法,效率不高,再想想还有什么
谷歌大神问了下,提到了一种快慢指针,利用两个指针,一个一次遍历一个节点,另一个一次遍历两个节点,只要能相遇 说明是有环的。
那么问题来了进入环后,这两个指针一定能够相遇吗?
分析一下吧
快指针一定是先进入环中,我们假设当慢指针进入环的时候,建立一个类似坐标的标识,
这里写图片描述
快指针为位置0,慢指针假设位置是n,
每遍历一次快指针到达的位置是
2/6
比如遍历3次,快指针回到0点
(2×3)/6=0;
同理慢指针从位置n为基点,开始遍历,遍历一次为
n/6
比如遍历3次到达位置1
(n+3)/6=1
假设经过t次遍历两者相遇,
(2t)/6=(n+t)/6
t=n;
也就是经过n次遍历两者是可以相遇的,
而n是一个常量值,
所以快慢指针是一定可以相遇的。
下面看看代码如何实现这种方法

bool fspoint(LIST* h)
{
 assert(h!=NULL);
 LIST *f;
 LIST *s;
 f=s=h;
 while(f!=NULL)
 {
  if(f==s && f!=h)
   return true;
  else
  {
   f=f->next;
   f=f->next;
   s=s->next;
  }
 }
 return false;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值