#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);
}