22. 【C语言】判断单链表是否有环(5_task)

算法思想:
因为是单链表,那么单链表内部成环的原因只会是尾结点的指针域指向链表中的某一个结点。那么单链表成环的形状只有下面三种形式:
在这里插入图片描述
不管单链表形状如何,处理的方法都是一致的。

  1. 建立单链表,因为单链表的建立无要求,就采用尾插法建立单链表。
  2. 设置链表内部有环,选取链表内某一个结点位置,尾结点的指针域指向该结点。此时链表内部成环。
  3. 判断单链表是否有环,处理的方法:自定义两个结点指针:ppre和pcur,初始时,ppre指向首结点,pcur指向链表的第二个结点,这样错开是避免后续判断出错。用一个循环控制ppre和pcur向后偏移。设置一个信号变量sign,每次循环就先判断这两个指针是否指向同一个结点,若是,sign为1,跳出循环,输出单链表中有环;否则,ppre向后偏移一个位置,pcur向后偏移两个位置。但凡链表内部有环,ppre和pcur必然出现重合,指向同一个结点。若是内部无环,则循环的条件需要考虑输入结点的奇偶个数问题。
  4. 解除链表内部的环,即将尾指针的下一个指向置空。
  5. 再次判断链表内部是否有环。

假设链表内部有环,ppre和pcur两个结点指针指向变化如下:
在这里插入图片描述
案例运行效果:
在这里插入图片描述
此时链表内各结点状态如下:
在这里插入图片描述
当解除链表内部环后,再次判断链表内部是否有环
在这里插入图片描述
此时链表内各结点状态如下:
在这里插入图片描述
完整代码如下:

#include<stdio.h>
#include<stdlib.h>
#define N 3
typedef struct linklist {
	int data;
	struct linklist *next;
}list,*plist;

void list_create(plist *pphead,plist *pptail,int key)
{
	plist pnew = (plist)calloc(1, sizeof(list));
	pnew->data = key;
	if (NULL == (*pphead))
	{
		*pphead = pnew;
		*pptail = pnew;
	}
	else {
		(*pptail)->next = pnew;
		*pptail = pnew;
	}
}

void setring(plist p, plist *pptail, int flag)		//设置单链表内部第n个结点位置开始成环
{
	int count = N-1;
	if (flag)
	{
		while (count > 0)
		{
			p = p->next;
			count--;
		}
		(*pptail)->next = p;
	}
}

void judgering(plist phead)		//判断单链表内部是否有环
{
	plist ppre = phead, pcur = phead->next;
	int sign=0;
	while (pcur && pcur->next)		//考虑无环链表输入结点的奇偶个数
	{
		
		if (ppre == pcur)
		{
			sign = 1;
			break;
		}
		ppre = ppre->next;
		pcur = pcur->next->next;
	}
	if (sign)
		printf("单链表内部有环\n");
	else
		printf("单链表内部无环\n");
}

void removering(plist *pptail,int signal)		//解除单链表内部的环
{
	if (signal)
		(*pptail)->next = NULL;
}

int main()
{
	plist phead = NULL, ptail = NULL;
	int key,flag,signal;
	printf("是否预设链表有环:【是:1;否:0】");
	scanf("%d", &flag);
	while (scanf("%d", &key) != EOF)
	{
		list_create(&phead, &ptail, key);
	}
	setring(phead, &ptail, flag);
	judgering(phead);
	printf("是否解除链表内部的环:【是:1;否:0】");
	scanf("%d", &signal);
	removering(&ptail, signal);
	judgering(phead);
	system("pause");
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值