判断链表是否成环

腾讯面试题:判断链表成环

如何判断一个单链表有无环,有两种方法:
1、指针计步法。
何为计步法呢?就是定义两个指针,p,q。当q每次移动一个位置,p随之从头开始移动到q的位置。当两个指针第一次相遇就分别记下p,q所走的步数。如果有环,q移动到末尾然后再到达一个中间位置,p从头开始移动到q的位置时,p,q第一次相遇时,他们分别走的步数肯定不一样。
2、快慢指针法。
定义两个指针,fast,low。fast每次走两步,low每次走一步。两个指针同时出发,有环的话,他们肯定会相遇,如果没环,肯定不会相遇。代码如下:

#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
	int data;
	struct node *next;
}Node;
void CreateList(Node *L,int length)//创建一个无环链表
{
	int i = 1;
	Node *tail = NULL;
	Node *newnode = (Node *)malloc(sizeof(Node));
	L->next = newnode;//创建一个头结点
	if (length<=0)
	{
		printf("新建的是一个空表\n");
		exit(0);
	}
	while (i <= length)
	{
		Node *newnode = (Node *)malloc(sizeof(Node));
		newnode->data = i;
		if (tail == NULL)
		{
			tail = L->next;
		}
		tail->next = newnode;
		tail = newnode;//tail时钟指向最末尾
		tail->next = NULL;
		i++;
	}
}
Node* CreateRList(Node *L, int length)//创建一个有环链表
{
	static int i = 1;
	Node *tail = NULL;
	Node *newnode = (Node *)malloc(sizeof(Node));
	L->next = newnode;//创建一个头结点
	if (length <= 0)
	{
		printf("新建的是一个空表\n");
		exit(0);
	}
	while (i <= length)
	{
		Node *newnode = (Node *)malloc(sizeof(Node));
		newnode->data = i;
		if (tail == NULL)
		{
			tail = L->next;
		}
		tail->next = newnode;
		tail = newnode;//tail时钟指向最末尾
		i++;
	}
	tail->next = L->next;
	return tail;
}
void PrintList(Node *L,int length)//打印出链表
{
	if (L==NULL)
	{
		printf("空链表\n");
		exit(0);
	}
	L = L->next;
	while (L->next != NULL)
	{
		L = L->next;
		printf("%5d", L->data);
		if (L->data >= length) {
			break;
		}
	}
}
int JudgeList1(Node *L,int length)//使用指针计步法
{
	Node *list1=L;
	int i = 0, j = 0;
	while (list1)//如果指针1不为空就一直执行,list1为q
	{
		Node *list2 = L;//list2为p,每次从头走到q的位置
		i = 0;
		while (list2)
		{
			if (list2 == list1)//当p,q第一次相遇就退出
			{
				if (i==j)
				{
					break;//如果相等就继续监测
				}else {
					printf("链表有环\n");
					return 1;
				}
			}
			list2 = list2->next;
			i++;
		}
		list1 = list1->next;
		j++;
	}
	printf("链表没有环\n");
	return 0;
}
void JudgeList2(Node *L,int length)//第二种判断方法
{
	Node *fast=L;
	Node *low=L;
	if (length <= 0||L==NULL)
	{
		printf("请重新生成链表\n");
		exit(0);
	}
	while (fast->next!=NULL && low->next !=NULL)//如果快慢指针->next不为空就继续执行
	{
		fast = fast->next->next;
		low = low->next;
		if (fast == NULL)
		{
			printf("没有环\n");
			break;
		}
		if (fast == low)
		{
			printf("有环\n");
			break;
		}
	}
	if (fast != low)
	{
		printf("没有环\n");
	}
}
int main(void)
{
	int length=100;
	Node *head = (Node *)malloc(sizeof(Node));
	head->next = NULL;
	Node *tail = (Node *)malloc(sizeof(Node));
	tail->next = NULL;
	
	tail=CreateRList(head, length);//创建一个有环链表
	//CreateList(head, length);
	//JudgeList1(head, length);
	JudgeList2(tail, length);
	JudgeList2(head, length);
	return 0;
}

总结:第一种方法时间复杂为o(n^2),比较耗时耗力,相比之下快慢指针时间复杂度o(n),就优秀的多了。因此常常使用快慢指针的方法进行判断。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值