1、实现单链表逆置
无头结点:
1 #include<stdio.h>
2 #include<stdlib.h>
3
4 typedef struct node{ 5 int data; 6 struct node *next; 7 }Node; 8
9 //创建链表
10 Node *CreateList(void){ 11 int val,i,n; 12 Node *head,*p,*q; 13
14 head=NULL; 15 printf("请输入您要建立的链表长度:\n"); 16 scanf("%d",&n); 17 printf("请输入您要输入的数据:\n"); 18 for(i=0;i<n;i++){ 19 scanf("%d",&val); 20 p=(Node*)malloc(sizeof(Node)); 21 p->data=val; 22 if(head==NULL) 23 head=q=p; 24 else
25 q->next=p; 26 q=p; 27 } 28 p->next=NULL; 29 return head; 30 } 31
32 //链表的逆置
33 Node *ReverseList(Node *head){ 34 Node *p,*q,*r; 35 p=head; 36 q=r=NULL; 37 while(p){ 38 q=p->next; 39 p->next=r; 40 r=p; 41 p=q; 42 } 43 return r; 44 } 45
46 //输出链表
47 void ShowList(Node *head){ 48 Node *p; 49 p=head; 50 while(p){ 51 printf("%d ",p->data); 52 p=p->next; 53 } 54 printf("\n"); 55 } 56
57 void main(){ 58 Node *head; 59
60 head=CreateList(); 61 printf("链表逆置前的数据:\n"); 62 ShowList(head); 63
64 head=ReverseList(head); 65 printf("链表逆置后的数据:\n"); 66 ShowList(head); 67 }
运行演示:
2、判断单链表是否有环
判断链表是否存在环的办法为:
设置两个指针(fast,slow),初始值都指向头指针,slow每次前进一步,fast每次前进两步,如果链表存在环,则fast必定先进入环,而slow后进入环,两个指针必定相遇。(当然,fast先行从头到尾部为NULL,则为无环链表)程序如下:
1 #include<stdio.h>
2 #include<stdlib.h>
3
4 typedef struct node{ 5 int elem; 6 struct node * next; 7 }Node, *NodeList; 8
9 bool IsExitsLoop(NodeList head){ 10 NodeList slow=head,fast=head; 11 while(fast && fast->next){ 12 slow=slow->next; 13 fast=fast->next->next; 14 if(slow==fast) 15 break; 16 } 17 return !(fast==NULL || fast->next==NULL); 18 } 19
20 void main(){ 21 //创建一个有环的单链表
22 NodeList head=NULL,p,q; 23 for(int i=1;i<=5;i++){ 24 p=(NodeList)malloc(sizeof(Node)); 25 p->elem=i; 26 if(head==NULL) 27 head=q=p; 28 else
29 q->next=p; 30 q=p; 31 } 32 p=(NodeList)malloc(sizeof(Node)); 33 p->elem=6; 34 q->next=p; 35 q=p; 36 q->next=head->next->next->next; 37 //判断单链表是否存在环
38 printf("单链表是否存在环: "); 39 bool b=IsExitsLoop(head); 40 printf("%s\n",b==false?"false":"true"); 41 }
运行结果显示:
3、如果单链表有环,则找到环的入口点
当fast若与slow相遇时,slow肯定没有遍历完链表,而fast已经在环内循环了n圈(1<=n),假设slow走了s步,而fast走了2s步(fast步数还等于s加上在环上多转的n圈),设环长为r,则:
2s = s + n*r;
s = n*r;
设整个链表长为L,入口环与相遇点距离为x,起点到环入口点的距离为a。
a + x = n*r;
a + x = (n-1)*r + r = (n-1)*r + L -a;
a = (n-1)r + (L – a – x);
(L – a – x)为相遇点到环入口点的距离,由此可知,从链表头到环入口点等于(n-1)循环内环+相遇点到环入口点,于是我们从链表头、与相遇点分别设一个指针,每次各走一步,两个指针必定相遇,且相遇第一点为环入口点。程序描述如下:
1 #include<stdio.h>
2 #include<stdlib.h>
3
4 typedef struct node{ 5 int elem; 6 struct node * next; 7 }Node, *NodeList; 8
9 //寻找环的入口点
10 NodeList FindLoopPort(NodeList head){ 11 NodeList slow=head,fast=head; 12 while(fast && fast->next){ 13 slow=slow->next; 14 fast=fast->next->next; 15 if(slow==fast) 16 break; 17 } 18 if(fast==NULL||fast->next==NULL) 19 return NULL; 20 slow=head; 21 while(slow!=fast){ 22 slow=slow->next; 23 fast=fast->next; 24 } 25 return slow; 26 } 27
28 void main(){ 29 //创建一个有环的单链表
30 NodeList head=NULL,p,q; 31 for(int i=1;i<=5;i++){ 32 p=(NodeList)malloc(sizeof(Node)); 33 p->elem=i; 34 if(head==NULL) 35 head=q=p; 36 else
37 q->next=p; 38 q=p; 39 } 40 p=(NodeList)malloc(sizeof(Node)); 41 p->elem=6; 42 q->next=p; 43 q=p; 44 q->next=head->next->next->next; 45 //寻找环的入口点
46 NodeList list=FindLoopPort(head); 47 printf("环的入口节点元素值为:%d\n",list->elem); 48 }
运行结果显示:
4、判断两个单链表是否相交,如果相交,给出相交的第一个点(两个链表都不存在环)
比较好的方法有两个:
一、将其中一个链表首尾相连,检测另外一个链表是否存在环,如果存在,则两个链表相交,而检测出来的依赖环入口即为相交的第一个点。
二、如果两个链表相交,那么两个链表从相交点到链表结束都是相同的节点,我们可以先遍历一个链表,直到尾部,再遍历另外一个链表,如果也可以走到同样的结尾点,则两个链表相交。这时我们记下两个链表length,再遍历一次,长链表节点先出发前进(lengthMax-lengthMin)步,之后两个链表同时前进,每次一步,相遇的第一点即为两个链表相交的第一个点。