单链表环的问题

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*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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值