判断循环链表是否有环

来源:互联网 发布:淘宝客自动转换工具 编辑:程序博客网 时间:2024/05/29 07:38
一共有2个方法:
方法一:
一共使用2个指针,分别是p和q
指针p每走一步就停下来,保存走到的位置
指针q每次都要从头结点开始走
这样走到某个位置的时候
2个指针走的步数会不一样
这样就说明有环
例如下图所示的循环链表
如果p走到6,再走一步就走到3
可是q走到3只需要走2步
到达相同的位置,但是步数不一样
这样就说明有环
 
方法二:快慢指针法
定义2个指针p,q
每次q走2个位置,p走1个位置,
如果有环的话
q走的快,就会绕回来,
而p走的慢,就会被绕回来的q追上
如果没有环的话,p和q永远不会相撞


#include <stdio.h>


#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0


typedef int Status;
typedef int ElemType;


typedef struct Node 
{
      ElemType data;
      struct Node *next;
}Node,*LinkList;


Status InitList(LinkList *L)
{
      *L=(LinkList)malloc(sizeof(Node));
      if(!(*L))
      {
            return ERROR;
      }
      (*L)->next=NULL;
      return OK;
}
int ListLength(LinkList L)
{
      int i=0;
      LinkList p=L->next;
      while(p)
      {
            i++;
            p=p->next;
      }
      return i;
}


void CreateListHead(LinkList *L,int n)//头插法创建循环链表
{
      LinkList p;
      int i;
      srand(time(0));
      *L=(LinkList)malloc(sizeof(Node));//malloc()这个函数分配完内存空间后
                                        //就会返回指向这个内存空间的指针
      (*L)->next=NULL;


      for(i=0;i<n;i++)
      {
            p=(LinkList)malloc(sizeof(Node));
            p->data=rand()%100+1;//随机产生100以内的数字
            p->next=(*L)->next;
            (*L)->next=p;//生成单链表(不是循环的),头插法就是把每次新生成的结点插到
            //头结点之后,之前已经插入的结点应当往后挪
            //所以把p的下一个结点的地址放到新生成的结点L的next域内
            //然后断开之前的链,把L的地址放到p的next域内
            /*这里的LinkList其实和int,char是一个意思
               只是是自己新定义的一种类型而已
               LinkList在定义的时候就定义成了一种指针
               特别指向链表的头结点
               而Node只是定义成了一种数据结构
               但是Node * s和LinkList s本质上没有区别
               都是指针,只是说法不同而已
               */




      }
}
void CreateListTail(LinkList *L,int n)
{
      LinkList p,r;
      int i;


      srand(time(0));
      *L=(LinkList)malloc(sizeof(Node));
      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)
      {
            LinkList cur2 = L;
            int pos2 = 0;
            while(cur2)
            {
                  if(cur2 == cur1)
                  {
                        if(pos1 == pos2)
                        {
                              break;
                        }
                        else 
                        {
                              printf("环的位置在第个结点处.\n\n",pos2);
                              return 1;
                        }




                  }
                  cur2 = cur2->next;
                  pos2++;
            }
            cur1 = cur1->next;
            pos1++;


      }
      return 0;
}


//利用快慢指针的方法
int HasLoop2(LinkList L)
{
      int strp1 = 1;
      int step2 = 2;
      LinkList p = L;
      LinkList q = L;


      while(p !=NULL && q !=NULL)
      {
            p = p->next;
            if(q->next !=NULL)
            {
                  q =q->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;
      ElemType e;
      int find;
      int tmp;


      i=InitList(&L);
      printf("初始化L后:ListLenfth(L)=%d\n",ListLength(L));


      printf("\n1.创建有环链表(尾插法)\n2.创建无环链表(头插法) \n3.判断链表是否有环  \n0.退出 \n");
      while(opp!='0')
      {
            scanf("%c",&opp);
            switch(opp)
            {
            case '1':
                  CreateListTail(&L,10);
                  printf("成功创建有环链表(头插法)\n");
                  printf("\n");
                  break;
            case '2':
                  CreateListHead(&L,10);
                  printf("成功创建无环链表(头插法)\n");
                  printf("\n");
                  break;
            case '3':
                  printf("方法一:\n\n");
                  if(HasLoop1(L))
                  {
                        printf("结论:链表有环\n\n\n");
                  }
                  else
                  {
                        printf("结论:链表无环\n\n\n");
                  }
                  printf("方法二:\n\n");
                  if(HasLoop2(L))
                  {
                        printf("结论:链表有环\n\n\n");


                  }
                  else
                  {
                        printf("结论:链表无环\n\n\n");
                  }
                  printf("\n");
                  break;
            case '0':
                  exit(0);
            }
      }

0 0