使用快慢指针判断的好处是:可以防止如果链表是类似“6”的,形状,也就是说尾指针不是直接连到头指针,而是它之后的指针,那么这种情况下传统的以头指针作为基准判断是否有循环的方法就可能陷入死循环。
给定一个链表,它可能是以NULL结尾的非循环链表,如图3-5所示;也可能是一个循环结构结尾的循环链表。已知这个链表的头指针,请编写一个函数来判断该链表是一个循环链表还是一个非循环链表,该函数不得对链表本身做任何修改。
算法:
让快慢两个指针从链表的头元素出发开始遍历
无限循环
如果快指针遇到了“NULL”指针
返回,该链表以“NULL”结束,是一个非循环链表
如果快指针追上或者超过了慢指针
返回,该链表是一个循环链表
让慢指针前进一个结点
让快指针前进两个结点
int determineTermination(node *head) {
if(!head) return 0;
node *fast, *slow;
fast = slow = head; //如果相等那循环只会运行一次
while(1) {
if (!fast ||!fast->next) //排除了fast->next->next不存在的情况
return 0;
else if (fast == slow || fast->next == slow)
return 1;
else {
slow = slow->next;
fast = fast->next->next;
}
}
}
我的版本:
int determineTermination(node *head)
{
if(!head) return 0;
node *fast, *slow;
slow=head;
fast=head->next;
while(fast!=NULL && fast->next!=NULL){
if (fast == slow || fast->next == slow)
return 1;
slow = slow->next;
fast = fast->next->next;
}
}
另外他人的版本:
function boolean hasLoop(Node startNode){
Node slowNode = Node fastNode1 = Node fastNode2 = startNode;
while (slowNode && fastNode1 = fastNode2.next() && fastNode2 = fastNode1.next()){
if (slowNode == fastNode1 || slowNode == fastNode2) return true;
slowNode = slowNode.next();
}
return false;
}
如果这是一个非循环链表,快指针将在遍历了n个节点后到达链表尾,快指针将在遍历了n个节点后达到链表尾,此时满指针只遍历了n/2个节点;因为总共遍历了(n+n/2=1.5n)个节点,所以这个算法将是O(n)级的。