判断单链表是否有环
摘自小甲鱼
#include "stdio.h" #include <stdlib.h> #include <time.h> #define OK 1 #define ERROR 0 #define TRUE 1 #define FALSE 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; }; /* 初始条件:链式线性表L已存在。 操作结果:返回L中数据元素的个数 */ int ListLength(LinkList L) { int i = 0; LinkList p = L->next; /* p指向第一个结点,注意,L指向的是头结点 */ while(p) { p = p->next; i++; } return i; } /* 随机产生n个元素的值,建立带头结点的单链线性表L(头插法) */ void CreateListHead(LinkList *L,int n) { srand(time(0)); /* 初始化随机数种子 */ /* 建立一个带头结点的单链表 */ // LinkList *L = (LinkList)malloc(sizeof(Node)); (*L)->next = NULL; for (int i = 0; i < n;i++) { LinkList p = (LinkList)malloc(sizeof(Node)); /* 生成新结点 */ p->data = rand() % 100 + 1; /* 随机生成100以内的数字 */ p->next = (*L)->next; (*L)->next = p; } } /* 随机产生n个元素的值,建立带头结点的单链线性表L(尾插法) */ void CreateListTail(LinkList *L,int n) { srand(time(0)); /* 初始化随机数种子 */ /* 建立一个带头结点的单链表 */ // LinkList *L = (LinkList)malloc(sizeof(Node)); LinkList r = *L; /* r为指向尾部的结点 */ for (int i = 0; i < n;i++) { LinkList p = (LinkList)malloc(sizeof(Node)); /* 生成新结点 */ p->data = rand() % 100 + 1; /* 随机生成100以内的数字 */ r->next = p; /* 将表尾终端结点的指针指向新结点 */ r = p; /* 将当前的新结点定义为表尾终端结点 */ } r->next = (*L)->next->next; /* 有环的 */ } /* 方法一:比较步数的方法 */ int HasCycle1(LinkList L) { LinkList cur1 = L; int pos1 = 0; //定义cur1的步数 // while(cur1) // { // LinkList cur2 = L; // int pos2 = 0; // while(cur2) // { // if(cur2==cur1) // { // if(pos1==pos2) // break; // else // { // printf("环的位置在第%d个结点处。\n\n", pos2); // return 1; // } // } // cur2 = cur2->next; // pos2++; // } // cur1 = cur1->next; // pos1++; // } // return 0; while(cur1->next!=NULL) { LinkList cur2 = L; //cur2永远都是从头结点出发 int pos2 = 0; //定义cur2的步数 cur1 = cur1->next; pos1++; for (pos2=0; cur2 != cur1;pos2++) //cur2一直向下走,直到与cur1指向的结点相同时停止 { cur2 = cur2->next; } if(pos1==pos2) //当走过的步数一致,说明没有环 continue; //刚开始写为break,所以执行结果一直是错的。 else { printf("环的位置在第%d个结点处。\n\n", pos2); return 1; } } return 0; } //方法二:利用快慢指针的方法 int HasCycle2(LinkList L) { LinkList p = L; //慢指针:一次走一步 LinkList q = L; //快指针:一次走两步 while(q!=NULL && q->next!=NULL) { q = q->next->next; p = p->next; printf("p:%d, q:%d \n", p->data, q->data); if(p==q) return 1; } return 0; } int main() { LinkList *L = (LinkList)malloc(sizeof(Node));; Status i; char opp; i = InitList(&L); printf("初始化L后:ListLength(L)=%d\n", ListLength(L)); printf("\n1.创建有环链表(尾插法) \n2.创建无环链表(头插法) \n3.判断链表是否有环 \n0.退出 \n\r"); while(opp!='0') { scanf("%c", &opp); switch(opp) { case '1': CreateListTail(&L, 10); printf("成功创建有环L(尾插法)\n"); printf("\n"); break; case '2': CreateListHead(&L, 10); printf("成功创建无环链表(头插法)\n"); printf("\n"); break; case '3': printf("方法一:\n\n"); if(HasCycle1(L)) { printf("结论:链表有环\n\n\n"); } else { printf("结论:链表无环\n\n\n"); } printf("方法二:\n\n"); if(HasCycle2(L)) { printf("结论:链表有环\n\n\n"); } else { printf("结论:链表无环\n\n\n"); } break; case '0': printf("退出\n\n\n"); break; } } }