链表是否构成环、环的长度以及环的入口点的求法
题目:判断一个链表是否构成环,并求出所构成环的长度,以及环的入口点。
基本思想:
(1)判断是否构成环的方法
定义快慢两个指针p1和p2,让这两个指针指向链表的头结点。假设该链表中有n个结点,让快指针比慢指针快两步,之后两个指针沿着链表向前走,若可以构成环,快指针总会比慢指针多走k圈,直到相遇;若不能构成环,则快指针和慢指针永远不可能相遇。
(2)求环的长度
若没有构成环,返回0,此时的该链表已经构成环。求环的长度。
(3)求环的入口点
同样,快指针走两步时慢指针走一步,于是有以下的推导。
假设,快指针走了m圈,慢指针走了n圈。分析如下图所示。
代码实现:
#include
#include
using namespace std;
typedef int DataType;
struct ListNode
{
DataType _data;
ListNode* _next;
ListNode(const DataType x)
:_data(x)
, _next(NULL)
{}
};
class List
{
typedef ListNode Node;
public:
List()
:_root(NULL)
{}
void Push(DataType x)
{
if (_root == NULL)
{
_root = new Node(x);
}
else
{
Node* tmp = _root;
while (tmp->_next)
{
tmp = tmp->_next;
}
tmp->_next = new Node(x);
}
}
Node* Find(DataType x)
{
Node* cur = _root;
while (cur)
{
if (cur->_data == x)
{
return cur;
}
cur = cur->_next;
}
return NULL;
}
Node* JudgeCircle() //判断是否带环
{
Node* slow = _root; //定义一个快指针和慢指针,快指针走两步,慢指针走一步
Node* fast = _root;
while (fast&&fast->_next)
{
fast = fast->_next->_next;
slow = slow->_next;
if (fast == slow)
{
return fast;
}
}
return NULL;
}
int GetCircleLength(Node* meet) //求环的长度
{
Node* tmp = JudgeCircle();
if (tmp == NULL)
{
return 0;
}
Node* cur = meet;
int count = 1;
while (cur->_next !=meet)
{
cur = cur->_next;
count++;
}
return count;
}
Node* GetEntryNode(Node* meetNode) //求环的入口点
{
Node* fast = _root;
Node* slow = meetNode;
while (fast != slow)
{
fast = fast->_next;
slow = slow->_next;
}
return fast;
}
void Printf()
{
Node* cur = _root;
while (cur)
{
cout << cur->_data << "->";
cur = cur->_next;
}
cout << "NULL" << endl;
}
protected:
Node* _root;
};
void Test()
{
List s1;
s1.Push(1);
s1.Push(2);
s1.Push(3);
s1.Push(4);
s1.Push(5);
s1.Push(6);
s1.Push(7);
s1.Printf();
ListNode* ret = NULL;
ret = s1.Find(7);
/*if (ret != NULL)
{
cout << "找到了" << endl;
}
else
{
cout << "没找到" << endl;
}*/
ret->_next =s1.Find(5);
ListNode* s = s1.JudgeCircle();
if (s != NULL)
{
cout << "可以构成环" << endl;
}
else
{
cout << "不能构成环" << endl;
}
cout <<"环的长度为:"<
_data << endl;
}
运行结果: