不用头指针,而是用指向终端结点的尾指针来表示循环链表,这个就是循环列表。如图:
那么要判断单链表中是否有环,主要有以下两种方法:
方法一:使用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); } } }