判断单链表中是否有环,计算出环的首地址 C语言实现
2014-06-24 12:44
288 查看
判断单链表中是否有环,如果有,得出进入环时首个节点的地址.
有环的定义是,链表的尾节点指向了链表中的某个节点。
如: ____________
↓ ↑
①->②->③->④->⑤->⑥
那么要判断单链表中是否有环,主要有以下两种方法:
方法一:使用p1、p2两个指针指向头节点,p1总是向前走,但p2每次都从头开始走,对于每个节点,看p1走的步数是否和p2一样。如图,当p1从6走到3时,用了6步,此时若p2从head出发,则只需两步就到3,因而步数不等,出现矛盾,存在环。而且这个点就是进入环时首个节点。(参考函数Plink
check_link_1(Plink head))
方法二:使用p1、p2两个指针指向头节点,p1每次向前走一步,p2每次向前走两步,若在某个时候p1 == p2,则存在环。然后p2指向头结点,使p1,p2每次向前走一步,进行比较p1,p2如果p1==p2那么这个节点就是入环时首个节点。
算法如下:如上图所示,如果①节点到③节点的距离为x,假设第一次移动时,p1 == p2时的节点是⑤的话,③到⑤的距离为y, ③到的距离为z。 所以我们可以得到第一次p1==p2时,那么p1和p2走的步数的差就是p1走过的步数,而且是z的倍数。x+y+mz=nz,所以x+y=(m-n)z。所以当x+y向前移动x时肯定会到达入环时首个节点。 x+y+x=(m-n)z+x。这样我们就可以求得入环首节点的的地址了。(参考函数Plink
check_link_1(Plink head))
代码如下所示:
有环的定义是,链表的尾节点指向了链表中的某个节点。
如: ____________
↓ ↑
①->②->③->④->⑤->⑥
那么要判断单链表中是否有环,主要有以下两种方法:
方法一:使用p1、p2两个指针指向头节点,p1总是向前走,但p2每次都从头开始走,对于每个节点,看p1走的步数是否和p2一样。如图,当p1从6走到3时,用了6步,此时若p2从head出发,则只需两步就到3,因而步数不等,出现矛盾,存在环。而且这个点就是进入环时首个节点。(参考函数Plink
check_link_1(Plink head))
方法二:使用p1、p2两个指针指向头节点,p1每次向前走一步,p2每次向前走两步,若在某个时候p1 == p2,则存在环。然后p2指向头结点,使p1,p2每次向前走一步,进行比较p1,p2如果p1==p2那么这个节点就是入环时首个节点。
算法如下:如上图所示,如果①节点到③节点的距离为x,假设第一次移动时,p1 == p2时的节点是⑤的话,③到⑤的距离为y, ③到的距离为z。 所以我们可以得到第一次p1==p2时,那么p1和p2走的步数的差就是p1走过的步数,而且是z的倍数。x+y+mz=nz,所以x+y=(m-n)z。所以当x+y向前移动x时肯定会到达入环时首个节点。 x+y+x=(m-n)z+x。这样我们就可以求得入环首节点的的地址了。(参考函数Plink
check_link_1(Plink head))
代码如下所示:
/* * 判断单链表中是否有环,如果有,得出进入环节点的首地址. */ #include <stdio.h> #include <stdlib.h> typedef struct link{ int data; struct link *next; }*Plink; #define LINK_MAX 10 /* 创建一个单链表 */ void create_link(Plink *head, int num) { Plink node=NULL; Plink next=NULL; if(*head == NULL){ *head = (Plink)malloc(sizeof(struct link)); if(*head == NULL){ exit(0); } (*head)->data = num; (*head)->next = NULL; return; } node = *head; while(node->next != NULL){ node = node->next; } next = (Plink)malloc(sizeof(struct link)); if(next == NULL){ exit(0); } next->data = num; next->next = NULL; node->next = next; return; } /* 在单链表中设定一个环,让尾节点指向链表中的第n个节点 */ int create_loop(Plink *head, int n) { int count=1; Plink node = *head; Plink n_node = NULL; if(head == NULL){ return -1; } while(node->next != NULL){ if(count == n){ n_node = node; } node = node->next; count++; } /* 尾节点和自身成一个环时 */ if(count == n){ n_node = node; } if(n_node == NULL){ return -1; } node->next = n_node; return 0; } /* 打印链表的前n个data的值 */ void print_link(Plink head, int n) { int count=0; Plink node = head; while((node != NULL) && (count < n)){ printf("%d->", node->data); node = node->next; count++; } printf("\n"); return; } /* * 使用p1、p2两个指针,p1总是向前走,但p2每次都从头开始走, * 对于每个节点,看p1走的步数是否和p2一样。数不等,存在环。 * 而且该点就是入环时首个节点的地址。 */ Plink check_link_1(Plink head) { int count1=0,count2=0; Plink p1=head, p2=head; while(p1){ /* p2每次都从头开始走 */ count2 = 0; p2=head; while(p2 && (p1 != p2)){ p2 = p2->next; count2++; } if((p1 == p2) && (count1 != count2)){ return p2; } p1=p1->next; count1++; } return NULL; } /* * 使用p1、p2两个指针,p1每次向前走一步,p2每次向前走两步, * 若在某个时候p1 == p2,则存在环. * 然后p1继续向前走,p2重头开始一步一步向前走,当p1 == p2时, * 那么该点就是入环时首个节点的地址 */ Plink check_link_2(Plink head) { int flag=0; Plink p1=head, p2=head; while(p2){ p1=p1->next; if(p2->next){ p2=p2->next->next; } if(p1 == p2){ flag=1; break; } } if(flag){ p2=head; while( p1!=p2 ){ p1=p1->next; p2=p2->next; } return p1; } return NULL; } /* 删除链表 */ void delete_link(Plink *head) { return; } int main() { int i=0,n=0; int ret=0; Plink root=NULL; Plink node=NULL; /* 创建一个单链表 */ for(i=1; i<=LINK_MAX; i++){ create_link(&root, i); } /* 在单链表中设定一个环,让尾节点指向链表中的第n个节点 */ n = 5; ret = create_loop(&root,n); if(ret){ printf("no\n"); }else{ printf("yes\n"); } /* 打印链表 */ n = 20; print_link(root,n); /* 检查该环 */ node = check_link_1(root); if(node == NULL){ printf("单链表中不存在环\n"); }else{ printf("单链表中存在环,进入环节点的首地址:%x, data:%d\n",node, node->data); } /* 删除链表 */ delete_link(&root); return 0; }
相关文章推荐
- 单链表的实现(包括就地逆转单链表,表排序, 合并单链表、判断表是否有环)
- memcpy用指针的实现通过判断地址是否重合解决掉字符串结束符('\0')问题
- 数据结构与算法分析笔记与总结(java实现)--链表17:无环单链表判断是否相交问题
- 用Java实现判断链表是否有环,环的大小,环的长度以及计算链表的长度
- 判断两个单链表是否相交--java实现
- 单链表的实现(包括就地逆转单链表,表排序, 合并单链表、判断表是否有环)
- 【C语言】判断单链表是否带环
- 数据结构与算法分析笔记与总结(java实现)--链表19:判断单链表是否相交问题
- 判断单链表是否有环的java实现
- Java判断单链表是否有环的两种实现方法
- 【数据结构】C语言判断链表是否为空,计算链表长度及链表排序算法
- C语言实现链表之单向链表(十二)判断链表是否为空和获取链表长度
- 判断单链表中是否有环,如果有环则找到环的入口地址
- 数据结构与算法分析笔记与总结(java实现)--数组7:判断单链表是否相交问题构建乘积数组
- 用C语言实现输入密码以星号显示并判断密码是否正确
- 练习:判断单链表是否为环--C实现
- 题目:代码实现判断单链表是否有环
- 判断两个单链表是否相交--java实现
- c语言实现判断两颗树是否同构
- Java判断单链表是否有环的两种实现方法