【是否带环】
基本思路:定义两个指针从头结点开始,一个一次向后走一步,一次走两步,循环,若能够走到NULL,则不带环,若走到两个指针相等,则带环。
代码如下:
pair<bool,PNode> HasCircle(PNode phead)//判断是否带环,带环的话环的长度,入口。 { assert(phead); //时间复杂度是O(n) PNode pcur = phead; PNode prev = pcur; int flag = 0; while (prev&&prev->_pNext) { pcur = pcur->_pNext; prev = prev->_pNext->_pNext; if (prev==pcur) { return make_pair(true,pcur); } } return make_pair(false,(PNode)NULL); }
【环长】
基本思路:判断完是否带环后,返回相遇位置,定义两个指针,一个整形count初始化为0,再从相遇位置开始,一个指针一次走一步,一个指针一次走两步,count++, 等到再次相遇时,返回count的值即为环长。
代码如下:
int LenOfCircle(PNode phead)//带环求环的长度 时间复杂度为O(n) { pair<bool,PNode> res = HasCircle(phead); if (!res.first) { return 0; } PNode pcur = res.second; PNode prev = pcur; int count = 0; while(true) { pcur = pcur->_pNext; prev = prev->_pNext->_pNext; count++; if (prev == pcur) { return count; } } }
【环的入口】
基本思路:
第一次相遇时的位置知道后,则从头到入口的距离和相遇点到入口的距离相等(后有具体证明),则可以让一个指针从头开始走,一个指针从相遇点开始走,走到两个指针相遇,则相遇点就是入口点。
证明:(理科生,所以用公式来证明)
求环长时,相遇点在5的地方,若pcur一步走两个,则pcur的路径为:l+R+h+R(也就是一圈然后在加上R),
prev的路径是:l+R,而这两个指针的路径又是有2倍的关系。
则:l+2R+h = 2*(l+R)
解上面的式子可以得到:l = h,也就是从头到入口的距离和从相遇点到入口的距离相等。
代码如下:PNode EnterOfCircle(PNode phead)//带环求环的入口点//以及求时间复杂度O(n) { pair<bool,PNode> res = HasCircle(phead); if (!res.first) { return 0; } PNode pcur = res.second; PNode prev = phead; while (true) { pcur = pcur->_pNext; prev = prev ->_pNext; if (prev == pcur) { return pcur; } } }