判断链表中是否有环链

思路:判断链表中是否有环,可以使用快慢指针(fast low)遍历链表实现,fast每次走两步,low每次走一步,如果他们在链表中相遇,则说明有环,否则fast提前遇上NULL,说明链表无欢。

关键代码:

//判断环
int link_list_judge(node *head)
{
	//定义fast low指针,分别从head开始遍历
	node *fast,*low;
	fast=low=head;
	//fast每次循环两次,low每次前进一位
	while(fast->next&&low->next)		//关键步骤:循环退出条件
	{
        //low指针出发
		low=low->next;
		//fast指针出发(并判断)
		if((fast=fast->next->next)==NULL)
		{
			printf("链表无环!\n");
			return 0;		
		}
		else if(fast==low)
		{
			printf("链表有环!\n");
			return 1;		//返回整型数值进行判断
		}
	}
	return 0;
}

循环退出条件:循环开始,需判断fast->next是否是有效节点,利用和low指针的与逻辑操作,可实现,当然这样也可实现判断链表可能为空的情况,fast指针指向第二个节点(不包含head)时,需判断fast当前存入的地址。

完整代码:

/*分析:链表中如果存在环,那么链表
		尾节点一定不指向NULL,并且会产生循环
	解题思路:对要判断的链表,从头结点开始,
	遍历链表,直到遇到第二个相同的节点

	具体解题思路:利用快慢指针(双指针)
	设计两个指针fast和low,fast和low从
	同一位置同时出发(head),fast每次
	走两步,low每次走一步,如果fast遇到
	NULL,说明该链表没环;
*/

#include <stdio.h>
#include <stdlib.h>

// 节点设计
typedef struct node
{
	int data;
	struct node *next;
} node;

// 函数声明
//  初始化节点
node *link_list_init(void);
// 头插
void link_list_add(node *head, int add_data);
// 尾插
void link_list_add_tail(node *head, int add_data);
// 遍历链表
void link_list_show(node *head);
// 生成环
void link_list_ring(node *head);
// 尾节点寻找函数
node *link_list_tail(node *head);
// 遍历带环链表
void link_list_show_ring(node *pos, node *head);
//判断环
int link_list_judge(node *head);

// 主函数(单向不循环链表)
int main(int argc, char const *argv[])
{
	// 创建空链表
	node *head = link_list_init();
	// 循环输入数据
	int cmd;
	while (1)
	{
		printf("Pls enter the num!:");
		scanf("%d", &cmd);
		while (getchar() != '\n')
			;
		if (cmd > 0)
		{
			link_list_add_tail(head, cmd); // 添加数据
			link_list_show(head);
		}
		else if (cmd == 0)
			link_list_ring(head); // 生成环
		else
		{						  // else
		    link_list_judge(head); // 判断环
			//printf("head_:%d\n",head->next->data);
		}
	}
	return 0;
}

// 初始化节点
node *link_list_init(void)
{
	// 申请堆空间
	node *new = malloc(sizeof(node));
	// 判断能否正常申请堆空间
	if (new == NULL)
	{
		printf("malloc failed\n");
		return NULL;
	}
	// 新节点数据域清空和指针域处理
	new->data = 0;
	new->next = NULL;
	// 返回新节点
	return new;
}

// 头插
void link_list_add(node *head, int add_data)
{
	// 申请新节点空间
	node *new = link_list_init();
	// 新节点数据域
	new->data = add_data;
	// 新节点指针域
	new->next = head->next;
	head->next = new;
}

// 尾插
void link_list_add_tail(node *head, int add_data)
{
	// 定义指针寻找尾节点
	node *pos = head;

	while (pos->next != NULL)
	{
		pos = pos->next;
	}
	// 参数传递给头函数进行头插入链
	link_list_add(pos, add_data);
}

// 遍历链表
void link_list_show(node *head)
{
	// 定义指针遍历链表
	node *pos = head->next;

	for (pos; pos != NULL; pos = pos->next)
		printf("%d ", pos->data);
	printf("\n");
}

// 遍历带环链表
void link_list_show_ring(node *pos, node *head)
{
	printf("环中链表:");
	node *u = pos;
	do
	{
		printf("%d ", u->data);
		u=u->next;
	}while(u!=pos);
	printf("\n");
}

// 生成环
void link_list_ring(node *head)
{
	if(head->next==NULL)
	{
		printf("空链表,头结点既是环本身!\n");
		return ;
	}
	int j=link_list_judge(head);
	if(j==1)
	{
		printf("停止生成链环!\n");
		return ;
	}
	printf("环节点之前的整链表:");
	link_list_show(head);
	// 自定义指向节点
	int dd;
	printf("请输入要从哪个数据开始成环:");
	scanf("%d", &dd);
	while (getchar() != '\n')
		;
	// 定义指针寻找目的节点
	node *pos = head->next;
	while (dd != pos->data)
	{
		pos = pos->next;
		if (pos == NULL)
		{
			printf("匹配失败!\n");
			return;
		}
	}
	// 匹配成功,tail指向该结点,形成环
	link_list_tail(head)->next = pos;
	printf("已形成环!\n");
	link_list_show_ring(pos, head);
}

// 尾节点寻找函数
node *link_list_tail(node *head)
{
	node *pos = head;
	while (pos->next != NULL)
		pos = pos->next;
	return pos;
}

//判断环
int link_list_judge(node *head)
{
	//定义fast low指针,分别从head开始遍历
	node *fast,*low;
	fast=low=head;
	//fast每次循环两次,low每次前进一位
	while(fast->next&&low->next)		//关键代码:循环结束条件
	{
		low=low->next;
		//双指针开始出发
		//由于fast要移动两位,为防止fast溢出链表,fast每次前进都需要检查当前fast结点
		if((fast=fast->next->next)==NULL)
		{
			printf("链表无环!\n");
			return 0;		
		}
		
		else if(fast==low)
		{
			printf("链表有环!\n");
			return 1;		//返回整型数值进行判断
		}
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值