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

typedef struct date_list{
    int data;
    struct date_list* next;
}mylist;

mylist* creatlist(int x,mylist* p)        //用一个元素创建链表
{
    if(NULL == p)                         //链表创建必须判空
    {
        p = malloc(sizeof(mylist));
        p->data = x;
        p->next = NULL;
    }
    return p;
}

mylist* insert_tail(int x, mylist* Head)   //在链表的尾部插入元素
{
    if(NULL == Head)                       //尾插如果插入链表为空创建链表
        Head = creatlist(x, Head);
    else
    {
        mylist *p = NULL,*q = NULL;
        for(p = Head; p->next != NULL; p = p->next )
            ;
        q = creatlist(x, q);
        p->next = q;
    }
    return Head;
}

mylist* dellist(mylist *Head)    //删除整个链表    在堆中自己开辟的空间必须释放掉
{                                           //定义变量是从栈中开辟空间先定义,空间地址大
    mylist *p = NULL, *q = NULL;
    if(NULL == Head)
        return Head;
    else
    {
        while(Head->next != NULL)
        {
            for(p = Head, q = Head->next; q->next != NULL; p = q, q = q->next)
                ;
            free(q);
            p->next = NULL;
        }
        free(Head);
        Head = NULL;           //删除掉链表的时候必须指控,防止野指针的出现
    }
    return Head;
}

void show(mylist *Head)            //列出链表中的元素
{
    mylist *p = NULL;
    if(NULL == Head)               
        printf("it's a NULL point");
    else
    {
        p = Head;
        do
        {
            printf("%d ",p->data );
            p = p->next;
        }while(p != NULL);
    }
    printf("\n");
}

mylist* find_tail(mylist *Head, int n)   //寻找链表的倒数第n个元素
{
    mylist *fast = Head, *low = NULL, *get_len = Head;
    int len = 1;
    if(Head == NULL||n<0)               //链表判空,而且倒数第n个节点,n必须为正整数
        return NULL;
    for(; get_len != NULL; get_len = get_len->next, len++)
        ;                               //这里是空语句
    if(len < n)                         //n还要小于等于链表节点的个数
        return NULL;
    for(;n != 1; n--)
        fast = fast->next;
    for(low = Head; fast->next != NULL; fast = fast->next, low = low->next )
        ;
    return low;
}

int creat_circl(mylist *Head, int n)   //让单链表生成环,即环中存在n个节点   这是为了实现后续功能函数进行测试加入的
{
    if(Head == NULL)
        return 0;
    else
    {
        find_tail(Head,1)->next = find_tail(Head,n);
        return 1;
    }
}

int is_circl(mylist *Head)            //判断单链表中是否存在环
{
    mylist *fast, *low;               //两个指针指向头,一个前进一步,一个前进两步,两个指针相遇则存在环
    if(Head == NULL)                  //快的指针指向空时不存在环
        return 0;
    else
    {
        for(fast =Head->next, low = Head; fast != low&&fast->next != NULL; fast=fast->next,fast=fast->next, low = low->next )
            ;
        if(fast == low)
        {
            printf("存在环\n");
            return 1;
        }
        else
        {
            printf("不存在环\n");
            return 0;
        }
    }
}

mylist *wic_circl(mylist *Head) //求出环节点:将环中节点打断(上述判断时相遇节点为环中节点),转换成'Y'字链表求第一个交叉节点,再还原该链表
{
    mylist *fast, *low, *t_Head, *t_low;
    int lenth_low = 0, lenth_len = 0, i;  
    if(Head == NULL)
        return Head;
    else                        //找出环中节点,将其的指针域用low记录下,并指为空。得到两个具有'Y'字特性的单链表,然后找出相同的第一个节点
    {                           //则为环节点,然后将指向空的节点的指针域指向记录的指针low打断节点的地址。
                                //找出相同的第一个节点:1.用双重循环做 空间复杂度:S(1),时间复杂度:O(n^2)
                                //2.计算出两个链表的长度。让长的链表先走长出的长度,然后两个链表再同步走,可以找出相同的第一个节点。
                                //   时间复杂度为O(max(m,n))   空间复杂度为:S(1)
        for(fast =Head->next, low = Head; fast != low&&fast->next != NULL; fast=fast->next,fast=fast->next, low = low->next )
            ;
        low = low->next;
        fast->next = NULL;
        for(t_Head = Head; t_Head != NULL; t_Head=t_Head->next)
            lenth_len++;
        for(t_low = low; t_low !=NULL; t_low=t_low->next)
            lenth_low++;
        if(lenth_low >= lenth_len)
        {
            for(i = 0, t_low = low; i<(lenth_low-lenth_len); i++)
                t_low = t_low->next;
            t_Head = Head;
        }
        else
        {
            for(i = 0, t_Head = Head; i<(lenth_len-lenth_low); i++)
                t_Head = t_Head->next;
            t_low = low;
        }
        for(; t_low != t_Head; t_low = t_low->next, t_Head = t_Head->next )
            ;
        fast->next = low;
        return t_low;
    }
}

mylist *get_no_circl(mylist *Head)                  //将一个带环的单链表转换成一个单链表   
{                                                   
    mylist *circl_begin = NULL, *p = Head;          
    if(is_circl(Head))
    {
        circl_begin = wic_circl(Head);    
        for(; p->next != circl_begin; p=p->next);   //第二次碰见环节点才进行打断环
        p=p->next;
        for(; p->next != circl_begin; p=p->next);        
        p->next = NULL;
    }
    return Head;
}

int main()
{
    int i;
    mylist *head = NULL;
    for(i=0; i<10; i++)                     //创建一个链表,该链表中的值为:0, 1, 2, 3, 4, 5, 6, 7, 8, 9
    {
        head = insert_tail(i, head);
    }
    show(head);                             //打印出链表的值
    printf("%d\n", find_tail(head,1)->data);//寻找链表中倒数第1个元素
    printf("%d\n", find_tail(head,3)->data);//寻找链表中倒数第3个元素
    printf("%d\n", find_tail(head,5)->data);//寻找链表中倒数第5个元素
    printf("%d\n", find_tail(head,6)->data);//寻找链表中倒数第6个元素
    printf("%d\n", find_tail(head,8)->data);//寻找链表中倒数第8个元素
    printf("%d\n", find_tail(head,9)->data);//寻找链表中倒数第9个元素
    printf("%d\n", find_tail(head,10)->data);//寻找链表中倒数第10个元素

    is_circl(head);
    creat_circl(head, 5);
    is_circl(head);
    printf("%d\n", wic_circl(head)->data);

    get_no_circl(head);
    show(head);

    dellist(head);
}