1.判断单链表是否有环
使用两个slow, fast指针从头开始扫描链表。指针slow 每次走1步,指针fast每次走2步。如果存在环,则指针slow、fast会相遇;如果不存在环,指针fast遇到NULL退出。
就是所谓的追击相遇问题:
代码示例如下:
//判断链表是否有环,如果无环返回NULL
ListNode* HasCircle(LinkList head){
if(head==NULL)
return NULL;
ListNode *slow=head;
ListNode *fast=head;
while(fast!=NULL){
slow=slow->next;//走一步
fast=fast->next;
if(fast!=NULL)
fast=fast->next;
else
return NULL;
//如果slow==fast,则有环
if(slow==fast)
return slow;
}//while条件为假,则退出循环
return NULL;
}
2.求有环单链表的环连接点位置
第一次碰撞点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;
代码示例如下:
//判断一个链表是否有环,如果有,返回环的入口点;如果无环,则返回NULL
ListNode* CircleEntrance(LinkList head){
if(head==NULL)
return NULL;
ListNode *slow=head;
ListNode *fast=head;
while(fast!=NULL){
slow=slow->next;//走一步
fast=fast->next;
if(fast!=NULL)
fast=fast->next;
else
return NULL;
//如果slow==fast,则有环
if(slow==fast)
break;
}//while条件为假,则退出循环
if(fast==NULL)//无环退出
return NULL;
else{
//求入口点位置
slow=head;
while(slow!=fast){
slow=slow->next;
fast=fast->next;
}
return slow;
}
}
3.求有环单链表的环长
已知环的起点,很容易求环的长度。
示例代码如下:
//如果一个链表有环,返回环的长度;无环,则返回0
int CircleLength(LinkList head){
if(head==NULL)
return 0;
ListNode *slow=head;
ListNode *fast=head;
while(fast!=NULL){
slow=slow->next;//走一步
fast=fast->next;
if(fast!=NULL)
fast=fast->next;
else
return 0;
//如果slow==fast,则有环
if(slow==fast)
break;
}//while条件为假,则退出循环
if(fast==NULL)//无环退出
return 0;
else{
slow=head;
while(slow!=fast){
slow=slow->next;
fast=fast->next;
}
//while()slow指向
int circlelen=1;
ListNode *p=slow;
//求环的长度
while(p->next!=slow){
++circlelen;
p=p->next;
}
return circlelen;
}
}
4.求有环单链表的链表长
上述3中求出了环的长度;2中求出了连接点的位置,就可以求出头结点到连接点的长度。两者相加就是链表的长度。
5.尾插法建立链表
typedef struct ListNode{
int data;
struct ListNode* next;
}ListNode,*LinkList;
//尾插法创建带环的链表
LinkList CreateLinkList(){
LinkList head=NULL;
ListNode *pre=NULL,*inter=NULL;
//尾插法建立链表
for(int i=1;i<=6;i++){
//创建结点
ListNode *temp=(ListNode*)malloc(sizeof(ListNode));
temp->data=i;
temp->next=NULL;
if(head==NULL){
head=temp;
pre=head;
}else{
pre->next=temp;
pre=temp;//尾插法
}
if(i==6)
inter=temp;//i==3值处为交叉点
}
pre->next=inter;//建立链表的环
return head;
}
6.测试代码
int main(){
LinkList head=CreateLinkList();
int circlelen=CircleLength(head);
if(!circlelen)
cout<<"no circle"<<endl;
else{
cout<<"has circle"<<endl;
cout<<"circle entrance is "<<circlelen<<endl;
}
return 0;
}