不用头指针,而是用指向终端结点的尾指针来表示循环链表,这个就是循环列表。如图:
那么要判断单链表中是否有环,主要有以下两种方法:
方法一:使用p、q两个指针,p总是向前走,但q每次都从头开始走,对于每个节点,看p走的步数是否和q一样。如图,当p从6走到3时,用了6步,此时若q从head出发,则只需两步就到3,因而步数不等,出现矛盾,存在环。
方法二:使用p、q两个指针,p每次向前走一步,q每次向前走两步,若在某个时候p == q,则存在环。
用随机的方法来生成一个链表,用两种方法判断是否有环。代码如下。
#include<stdio.h>
#include "malloc.h"
#include <stdlib.h>
#include <time.h>
#define OK 1
#define ERROR 0
#define TRUE 1
# define PALSE 0
typedef int Status;//Status是函数的类型其值是函数的状态码,如ok
typedef int ElemType;//ElemType类型是根据实际情况而定这里设定为int
typedef struct Node
{
ElemType data;
struct Node *next;
}Node,*LinkList;
//初始化带头结点的空链表
Status InitList(LinkList *L)
{
*L = (LinkList)malloc(sizeof(Node));//产生头结点,便是l指向此节点
if (!(*L))//储存分配失败
return ERROR;
(*L)->next=NULL;// 指针为空
return OK;
}
int ListLength(LinkList L)
{
int i=0;
LinkList p=L->next;//p指向第一个节点
while (p)
{
i++;
p=p->next;
}
return i;
}
//随机产生n个元素的值,建立表头节点的单链表l
void CreateListHead(LinkList *L,int n)
{
LinkList p;
int i;
srand(time(0));//初始化随机种子
*L = (LinkList)malloc(sizeof(Node));//l为整个线性表
(*L)->next=NULL;
for (i=0;i<n;i++)
{
p=(LinkList)malloc(sizeof(Node));//生成新的节点
(*L)->data=rand()%100+1;//随机生成100一类的数字
p->next=p;//将表尾的终端节点的指针指向新节点
(*L)->next=p;//将当前的新节点定义为表尾的终端节点
}
}
void CreateListTail(LinkList *L,int n)
{
LinkList p,r;
int i;
srand(time(0));//初始化随机种子
*L = (LinkList)malloc(sizeof(Node));//l为整个线性表
(*L)->next=NULL;
r=*L;
for (i=0;i<n;i++)
{
p=(Node *)malloc(sizeof(Node));//生成新的节点
p->data=rand()%100+1;
r->next=p;
r=p;
}
r->next=(*L)->next->next;
}
int HasLoop1(LinkList L)
{
LinkList cur1=L;//定义重点
int pos1=0;//重点的参数
while(cur1)//cur1存在
{
LinkList cur2=L;//定义cur2
int pos2 =0;
while(cur2)
{
if (cur1==cur2)
{
if(pos1==pos2)
break;
else
{
printf("环的位置在%d个节点处\n\n",pos2);
return 1;
}
}
cur2=cur2->next;
pos2++;
}
cur1=cur1->next;//如果发现没环,继续下一个节点
pos1++;
}
return 0;
}
int HasLoop2(LinkList L)
{
int step1=1;
int step2=2;
LinkList p=L;
LinkList q=L;
while (p!= NULL && q!=NULL && q->next!=NULL)
{
p= p->next;
if(q->next!=NULL)
q=q->next->next;
printf("p:%d,q:%d\n",p->data,q->data);
if (p==q)
return 1;
}
return 0;
}
int main()
{
LinkList L;
Status i;
char opp='a';
ElemType e;
int find;
int tmp;
i = InitList(&L);
printf("初始化L后:ListLength=%d\n",ListLength);
printf("\n1.创建有环链表L(尾插法)\n2.创建的无环列表L(头插法)\n3.判断是都有环\n0.退出");
while (opp!='0')
{
scanf("%c",&opp);
if(opp=='0')
return
printf("\n");
switch(opp)
{
case '1':
CreateListTail(&L,10);
printf("成功创建有环列表L(尾插法)\n");
break;
case '2':
CreateListHead(&L,10);
printf("成功创建无环列表L(尾插法)\n");
break;
case '3':
printf("方法一:\n\n");
if (HasLoop1(L))
{
printf("结论:链表有环\n\n\n");
}
else
{
printf("结论:链表无环\n\n");
}
printf("方法二:\n\n");
if (HasLoop2(L))
{
printf("结论:链表有环\n\n\n");
}
else
{
printf("结论:链表无环\n\n");
}
printf("*************************************************************************\n");
break;
case '0':
exit(0);
}
}
}