判断链表是否有环的:
如图,如果单链表有环,则在遍历时,在通过6之后,会重新回到3,那么我们可以在遍历时使用两个指针,看两个指针是否相等。
方法一:使用p、q两个指针,p总是向前走,但q每次都从头开始走,对于每个节点,看p走的步数是否和q一样。如图,当p从6走到3时,用了6步,此时若q从head出发,则只需两步就到3,因而步数不等,出现矛盾,存在环
方法二:使用p、q两个指针,p每次向前走一步,q每次向前走两步,若在某个时候p == q,则存在环。
代码如下:
#include <stdio.h>
struct node{
int data;
struct node *next;
};
typedef struct node Node;
#define SIZE sizeof(Node)
int num=0;//节点个数
//创建节点
Node* creteNode(int d)
{
Node* pn=(Node *)malloc(SIZE);
pn->data=d;
pn->next=NULL;
return pn;
}
//创建有环链表
void creatList_hashuan(Node** h)
{
Node* pn=NULL;
Node* p=NULL;
int d;
printf("请输入数据\n");
scanf("%d",&d);
pn=creteNode(d);
*h=pn;
p=*h;
num++;
while(1)
{
printf("请输入数据\n");
scanf("%d",&d);
if(d==0)
break;
pn=creteNode(d);
num++;
p->next=pn;
p=p->next;
}
p->next=(*h)->next->next;
}
void creatList(Node** h)
{
Node* pn=NULL;
Node* p=NULL;
int d;
printf("请输入数据\n");
scanf("%d",&d);
pn=creteNode(d);
*h=pn;
p=*h;
num++;
while(1)
{
printf("请输入数据\n");
scanf("%d",&d);
if(d==0)
break;
pn=creteNode(d);
num++;
p->next=pn;
p=p->next;
}
}
//比较步数的方法
int Loop1(Node* h)
{
Node* p=h;
int pos1=0;//步数1
while(p)
{
Node* p1=h;
int pos2=0;
while(p1)
{
if(p==p1)
{
if(pos1==pos2)
break;
else
{
printf("环的位置在第%d个节点处\n",pos2);
return 1;
}
}
p1=p1->next;//如果没有发现环的存在,继续下一个节点
pos2++;
}
p=p->next;
pos1++;
}
return 0;
}
//利用快慢指针的方法
int Loop2(Node* h)
{
Node* p=h;
Node* q=h;
while(p!=NULL && q!=NULL && q->next!=NULL)
{
p=p->next;
if(q->next->next!=NULL)
{
q=q->next->next;
}
else
{
printf("q指针走两步的话走出链表的范围了。所以只走一步:\n");
q=q->next;
}
printf("p:%d,q:%d\n",p->data,q->data);
if(p==q)
{
printf("该链表有环!\n");
return 1;
}
}
return 0;
}
//打印有环链表
void print(Node* h)
{
printf("list:\n");
int i;
for(i=0;i<num;i++)
{
printf("%d ",h->data);
h=h->next;
}
printf("\n");
}
//打印无环链表
void print1(Node* h)
{
printf("list:\n");
while(h)
{
printf("%d ",h->data);
h=h->next;
}
printf("\n");
}
int main()
{
Node* head=NULL;
int d;
printf("-----------------------------\n");
printf("---1.创建无环链表---\n");
printf("---2.创建有环链表---\n");
printf("-----------------------------\n");
printf("请输入您的选项:");
scanf("%d\n",&d);
getchar();
switch(d)
{
case 1:
creatList_hashuan(&head);
print(head);
Loop1(head);
Loop2(head);
break;
case 2:
creatList(&head);
print1(head);
Loop1(head);
Loop2(head);
break;
}
return 0;
}
其实我觉得最简单,最暴力,也是我的第一反应就是打印链表,如果有环,会循环打印。
void print1(Node* h)
{
printf("list:\n");
while(h)
{
printf("%d ",h->data);
h=h->next;
}
printf("\n");
}
这样去打印如果是有环会循环打印。