1.判断单链表是否有环
使用两个slow, fast指针从头开始扫描链表。指针slow 每次走1步,指针fast每次走2步。如果存在环,则指针slow、fast会相遇;如果不存在环,指针fast遇到NULL退出。
就是所谓的追击相遇问题:
2.求有环单链表的环长
在环上相遇后,记录第一次相遇点为Pos,之后指针slow继续每次走1步,fast每次走2步。在下次相遇的时候fast比slow正好又多走了一圈,也就是多走的距离等于环长。
设从第一次相遇到第二次相遇,设slow走了len步,则fast走了2*len步,相遇时多走了一圈:
环长=2*len-len。
3.求有环单链表的环连接点位置
第一次碰撞点Pos到连接点Join的距离=头指针到连接点Join的距离,因此,分别从第一次碰撞点Pos、头指针head开始走,相遇的那个点就是连接点。
在环上相遇后,记录第一次相遇点为Pos,连接点为Join,假设头结点到连接点的长度为LenA,连接点到第一次相遇点的长度为x,环长为R。
第一次相遇时,slow走的长度 S = LenA + x;
第一次相遇时,fast走的长度 2S = LenA + n*R + x;
所以可以知道,LenA + x = n*R; LenA = n*R -x;
4.求有环单链表的链表长
上述2中求出了环的长度;3中求出了连接点的位置,就可以求出头结点到连接点的长度。两者相加就是链表的长度。
编程实现:
下面是代码中的例子:
具体代码如下:
#include <stdio.h>
#include <stdlib.h>
typedef struct node{
int value;
struct node *next;
}LinkNode,*Linklist;
/// 创建链表(链表长度,环节点起始位置)
Linklist createList(){
Linklist head = NULL;
LinkNode *preNode = head;
LinkNode *FifthNode = NULL;
for(int i=0;i<6;i++){
LinkNode *tt = (LinkNode*)malloc(sizeof(LinkNode));
tt->value = i;
tt->next = NULL;
if(preNode == NULL){
head = tt;
preNode = head;
}
else{
preNode->next =tt;
preNode = tt;
}
if(i == 3)
FifthNode = tt;
}
preNode->next = FifthNode;
return head;
}
///判断链表是否有环
LinkNode* judgeRing(Linklist list){
LinkNode *fast = list;
LinkNode *slow = list;
if(list == NULL)
return NULL;
while(true){
if(slow->next != NULL && fast->next != NULL && fast->next->next != NULL){
slow = slow->next;
fast = fast->next->next;
}
else
return NULL;
if(fast == slow)
return fast;
}
}
///获取链表环长
int getRingLength(LinkNode *ringMeetNode){
int RingLength=0;
LinkNode *fast = ringMeetNode;
LinkNode *slow = ringMeetNode;
for(;;){
fast = fast->next->next;
slow = slow->next;
RingLength++;
if(fast == slow)
break;
}
return RingLength;
}
///获取链表头到环连接点的长度
int getLenA(Linklist list,LinkNode *ringMeetNode){
int lenA=0;
LinkNode *fast = list;
LinkNode *slow = ringMeetNode;
for(;;){
fast = fast->next;
slow = slow->next;
lenA++;
if(fast == slow)
break;
}
return lenA;
}
///环起始点
///如果有环, 释放空空间时需要注意.
LinkNode* RingStart(Linklist list, int lenA){
if (!list || lenA <= 0){
return NULL;
}
int i = 0;
LinkNode* tmp = list;
for ( ; i < lenA; ++i){
if (tmp != NULL){
tmp = tmp->next;
}
}
return (i == lenA)? tmp : NULL;
}
///释放空间
int freeMalloc(Linklist list, LinkNode* ringstart){
bool is_ringstart_free = false; //环起始点只能被释放空间一次
LinkNode *nextnode = NULL;
while(list != NULL){
nextnode = list->next;
if (list == ringstart){ //如果是环起始点
if (is_ringstart_free)
break; //如果第二次遇到环起始点addr, 表示已经释放完成
else
is_ringstart_free = true; //记录已经释放一次
}
free(list);
list = nextnode;
}
return 0;
}
int main(){
Linklist list = NULL;
LinkNode *ringMeetNode = NULL;
LinkNode *ringStartNode = NULL;
int LenA = 0;
int RingLength = 0;
list = createList();
ringMeetNode = judgeRing(list); //快慢指针相遇点
if(ringMeetNode == NULL)
printf("No Ring\n");
else{
printf("Have Ring\n");
RingLength = getRingLength(ringMeetNode); //环长
LenA = getLenA(list,ringMeetNode);
printf("RingLength:%d\n", RingLength);
printf("LenA:%d\n", LenA);
printf("listLength=%d\n", RingLength+LenA);
}
ringStartNode = RingStart(list, LenA); //获取环起始点
freeMalloc(list, ringStartNode); //释放环节点, 有环时需要注意. 采纳5楼建议
return 0;
}
http://www.cnblogs.com/xudong-bupt/p/3667729.html