spy 发表于 2015-3-27 17:22:52

有环链表的判断

本帖最后由 spy 于 2015-3-27 17:30 编辑

#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>

struct Node
{
      int data;
      struct Node * next;
};

struct Node *CreateList();
void ListTraverse(struct Node *);
int IsEmpty(struct Node *);
int ListLength(struct Node *);
void GenerateLoopListTail(struct Node *, int);
//int HaveLoop(struct Node *, int);
int HaveLoop2(struct Node *);
void DestroyList(struct Node *, int);

void main()
{
      struct Node *head = NULL;
      int n, i, len=0, j=0;
      char ch;
      printf("\n");
      printf("------------------------\n\n");
      printf(" 1.初始化链表\n 2.创建有环链表(尾插法)\n 3.判断链表是否有环\n 0.退出\n\n 请选择您的操作: ");
      scanf("%d", &n);
      putchar('\n');

      while(n)
      {
                switch(n)
                {
                case 1:
                        {
                              head = CreateList();
                              len = ListLength(head);
                              if(IsEmpty(head))
                              {
                                        printf("链表为空,请初始化链表!\n\n");
                                        break;
                              }
                              else
                              {
                                        ListTraverse(head);
                                        break;
                              }
                        }

                case 2:
                        {
                              if(IsEmpty(head))
                              {
                                        printf("链表为空,请初始化链表!\n\n");
                                        break;
                              }
                              else
                              {
                                        if(j)//j=0,则创建有环链表, 否则重新输入
                                        {
                              while(1)
                                                {
                                                      printf("当前已经是有环链表, 是重新建立链表还是放弃当前操作?(Y/N)\n");
                                                      fflush(stdin);
                                                      ch = getchar();
                                                      putchar('\n');
                                                      if('Y'==toupper(ch))
                                                      {
                                                                j = 0;
                                                                DestroyList(&head, len);
                                                                head = CreateList();
                                                                if(IsEmpty(head))
                                                                {
                                                                        printf("链表为空,请初始化链表!\n\n");
                                                                        goto SELECT;
                                                                }
                                                                else
                                                                {
                                                                        ListTraverse(head);
                                                                        goto SELECT;
                                                                }
                                                      }
                                                      else
                                                                if('N'==toupper(ch))
                                                                {
                                                                        goto SELECT;
                                                                }
                                                                else
                                                                {
                                                                        printf("error!\n");
                                                                }
                                                }
                                        }
                                        printf("输入要形成环的结点位置\n");
                                        scanf("%d", &i);
                                        len = ListLength(head);
                                        while(i<1 || i>len-1)
                                        {
                                                printf("无法形成环, 是重新输入还是放弃当前操作?(Y/N)\n");
                                                fflush(stdin);             //之前输入的回车符还存在缓冲区,需要清除后缓冲区才能正确接受当前的输入
                                                ch = getchar();
                                                if('N'==toupper(ch))
                                                {
                                                      putchar('\n');
                                                      goto SELECT;
                                                }
                                                else
                                                      if('Y'==toupper(ch))
                                                      {
                                                                printf("输入要形成环的结点位置\n");
                                                                scanf("%d", &i);
                                                      }
                                                      else
                                                      {
                                                                printf("error!\n");
                                                      }
                                        }
                                        GenerateLoopListTail(head, i);
                                        j++;
                                        printf("有环链表已形成!\n\n");
                              }
                              break;
                        }
                case 3:
                        {
                              if(IsEmpty(head))
                              {
                                        printf("链表为空,请初始化链表!\n\n");
                                        break;
                              }
                              else
                              {
                                        //if(HaveLoop(head, len))
                                        if(HaveLoop2(head))
                                        {
                                                printf("有环, 环的位置在第%d个结点\n\n", i);
                                        }
                                        else
                                        {
                                        printf("无环\n\n");
                                        }
                              }
                              break;
                        }

                default:
                        {
                              printf("您的输入有误, 请重新输入选择菜单!\n\n");
                        }
                }

SELECT: printf("请选择您的操作: ");
                scanf("%d", &n);
                if(1==n && len!=0)
                {
                        DestroyList(&head, len);
                }
                putchar('\n');
      }
}

struct Node *CreateList()
{
      int n=1, value;
      struct Node * head=NULL;
      struct Node * p, *q;
      printf("输入结点的值, 输入0完成初始化\n");
      scanf("%d", &value);
      while(!value)
      {
                printf("至少需要输入一个元素, 重新输入还是放弃当前操作? (Y/N)\n");
                fflush(stdin);
                if('N'==toupper(getchar()))
                {
                        putchar('\n');
                        return head;
                }
                else
                {
                        printf("输入结点的值, 输入0完成初始化\n");
                        scanf("%d", &value);
                }
      }
      head = (struct Node *)malloc(sizeof(struct Node));
      p = head;
      while(value)
      {
                q = (struct Node *)malloc(sizeof(struct Node));
                q->data = value;
                p->next = q;
                p= q;
                scanf("%d", &value);
      }
      q->next = NULL;
      return head;
}

void ListTraverse(struct Node *head)
{
      struct Node *p = head;
      p = p->next;
      printf("**********链表中的元素**********\n");
      while(p)
      {
                printf("%5d", p->data);
                p = p->next;
      }
      printf("\n\n");
}

int IsEmpty(struct Node *head)
{
      if(NULL == head)
                return 1;
      else
                return 0;
}

void GenerateLoopListTail(struct Node *head, int i)
{
      struct Node *p = head, *q = NULL;
      int j = 0;
      while(p->next!=NULL)
      {
                while(++j<i)
                {
                        p = p->next;
                }
                if(j==i)
                {
                        q = p->next;
                }
                p = p->next;
      }
      p->next = q;

}

int ListLength(struct Node *head)
{
      struct Node *p = head;
      int i=0;
      if(IsEmpty(head))
      {
                return 0;
      }
      while(p->next)
      {
                p = p->next;
                i++;
      }
      return i;
}

/*int HaveLoop(struct Node *head, int len)
{
      struct Node *p=head, *q;
      int cur1=0, cur2;
      while(cur1<=len+1)
      {
                cur2 = 0;
                q = head;
                while(cur2<cur1 && p!=q)
                {
                        q = q->next;
                        cur2++;
                }
                if(p == q)
                {
                        if(cur2!=cur1)
                        {
                              return 1;
                        }
                        else
                        {
                              if(cur2==len+1)
                              {
                                        return 0;
                              }
                        }
                }
                p = p->next;
                cur1++;
      }
}
*/


//使用快慢指针, 效率较高
int HaveLoop2(struct Node *head)
{
      struct Node *p, *q;
      p = q = head;
      do
      {
                p = p->next;
                q = q->next->next;
      }while( p!=q && !(q->next==NULL || q->next->next==NULL) );
      if(p==q)
      {      
                return 1;
      }
      else
      {
                return 0;
      }
}

void DestroyList(struct Node **head, int len)
{
      struct Node *p, *q;
      int i=0;
      p = q = (*head)->next;
      while(++i<len)
      {
                q = p->next;
                free(p);
                p = q;
      }
      free(p);
      free(*head);
}

citian3094 发表于 2015-5-19 18:33:25

谢谢分享!!

逆战时代 发表于 2015-5-21 20:03:55

看看。。
页: [1]
查看完整版本: 有环链表的判断