腾讯面试题:判断链表成环
如何判断一个单链表有无环,有两种方法:
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),就优秀的多了。因此常常使用快慢指针的方法进行判断。