判断单链表是否有环及相关引申问题
2012-09-18 16:24
225 查看
主要有如下问题:
1.判断单链表是否有环
2.求环的长度
3.找出环的入口节点
4.求带环链表长度
思路:
1. 判断是否有环,首先想到的思路是利用Hashmap存储访问过的节点,然后每次访问下一个节点前先判断节点是否在Hashmap中存在。
一旦存在,则存在环。这种解法需要格外的存储空间,并不是最优解。
另一种思路是追赶法,用两个指针ptr_fast,ptr_slow同时指向链表的头部,ptr_slow一次移动一步,[b]ptr_fast一次移动两步,如果最终ptr_slow和ptr_fast重合则说明链表有环,如果ptr_fast走到空指针(链表的结尾)则说明链表无环。[/b]
证明如下:
设ptr_fast每次走X步,ptr_slow单位时间走Y步;链表环内的节点数是C,链表环外节点数是Q,我们有
X*t-Y*t = n*C --> t= n*C / (X-Y) -->需保证t(多少次)是正整数,所以 X-Y = 1。
指针移动的次数为 (X+Y)*t = (X+Y)*n*C / (X-Y) -->使移动次数最少, 即X+Y最少,所以X=2,Y=1
2. 求环的长度,只要ptr_fast,ptr_slow在环中再走一次,再次相遇所需要的操作数便是环的长度。需注意,由于X = 2Y,所以再次相遇的点与首次相遇的点是同一个节点。
3. 找出环的入口节点。有定理:相遇点到入口点的距离 = 头节点到入口点的距离,因此令ptr_fast重新指向链表的头节点,然后ptr_fast和ptr_slow同时一次移动一步,当ptr_slow和ptr_fast再次重合时该节点指针就是环的入口节点指针。
定理证明如下:
当ptr_fast若与ptr_slow相遇时,ptr_slow肯定没有走遍历完链表,而ptr_fast已经在环内循环了n圈(1<=n)。假设ptr_slow走了s步,则ptr_fast走了2s步(ptr_fast步数还等于s 加上在环上多转的n圈),设环长为r,则:
2s = s + nr
s= nr
设整个链表长L,入口环与相遇点距离为x,起点到环入口点的距离为a。
a + x = s = nr
a + x = (n – 1)r +r = (n-1)r + L - a
a = (n-1)r + (L – a – x)
(L – a – x)为相遇点到环入口点的距离,由此可知,从链表头到环入口点等于(n-1)循环内环+相遇点到环入口点。
4. 求整个带环链表长度。根据第2问环的长度和第3问头结点到环入口的距离,即可得到整个带环链表的长度。
代码:
1.判断单链表是否有环
2.求环的长度
3.找出环的入口节点
4.求带环链表长度
思路:
1. 判断是否有环,首先想到的思路是利用Hashmap存储访问过的节点,然后每次访问下一个节点前先判断节点是否在Hashmap中存在。
一旦存在,则存在环。这种解法需要格外的存储空间,并不是最优解。
另一种思路是追赶法,用两个指针ptr_fast,ptr_slow同时指向链表的头部,ptr_slow一次移动一步,[b]ptr_fast一次移动两步,如果最终ptr_slow和ptr_fast重合则说明链表有环,如果ptr_fast走到空指针(链表的结尾)则说明链表无环。[/b]
证明如下:
设ptr_fast每次走X步,ptr_slow单位时间走Y步;链表环内的节点数是C,链表环外节点数是Q,我们有
X*t-Y*t = n*C --> t= n*C / (X-Y) -->需保证t(多少次)是正整数,所以 X-Y = 1。
指针移动的次数为 (X+Y)*t = (X+Y)*n*C / (X-Y) -->使移动次数最少, 即X+Y最少,所以X=2,Y=1
2. 求环的长度,只要ptr_fast,ptr_slow在环中再走一次,再次相遇所需要的操作数便是环的长度。需注意,由于X = 2Y,所以再次相遇的点与首次相遇的点是同一个节点。
3. 找出环的入口节点。有定理:相遇点到入口点的距离 = 头节点到入口点的距离,因此令ptr_fast重新指向链表的头节点,然后ptr_fast和ptr_slow同时一次移动一步,当ptr_slow和ptr_fast再次重合时该节点指针就是环的入口节点指针。
定理证明如下:
当ptr_fast若与ptr_slow相遇时,ptr_slow肯定没有走遍历完链表,而ptr_fast已经在环内循环了n圈(1<=n)。假设ptr_slow走了s步,则ptr_fast走了2s步(ptr_fast步数还等于s 加上在环上多转的n圈),设环长为r,则:
2s = s + nr
s= nr
设整个链表长L,入口环与相遇点距离为x,起点到环入口点的距离为a。
a + x = s = nr
a + x = (n – 1)r +r = (n-1)r + L - a
a = (n-1)r + (L – a – x)
(L – a – x)为相遇点到环入口点的距离,由此可知,从链表头到环入口点等于(n-1)循环内环+相遇点到环入口点。
4. 求整个带环链表长度。根据第2问环的长度和第3问头结点到环入口的距离,即可得到整个带环链表的长度。
代码:
#include "stdafx.h" #include <iostream> using namespace std; //the length of circum const int length = 22; //define the starting node of loop const int circularNum = 11; struct node{ int value; struct node *next; }; /** Create linklist containing nodes with value from 0 to length * parameter: num, which the last pointer points to, in order to create circular linklist */ node *createCircularLinklist(int num){ node *head,*last,*p,*temp; head=(node *)malloc(sizeof(node)); last=(node *)malloc(sizeof(node)); for(int i=0;i<length;i++){ p=(node *)malloc(sizeof(node)); p->value = i; p->next = NULL; if(i==0) head->next = p; if(i==num) temp = p; //if(i=num) temp = p; low-level mistake! last->next = p; last = p; } last->next = temp; //last points to the temp to create circum return head->next; } //print linklist void traverse(node *ptr){ int count = 0; while(ptr!=NULL){ if(count>length) break; cout<<ptr->value; if(ptr->next!=NULL) cout<<" -> "; ptr=ptr->next; count++; } cout<<endl; } /** * 1.Judge if the linklist is circular 2.Find the length of circum and the linklist 3.Find the starting node */ int isCircular(node *list){ bool isLoop = false; if(list==NULL) return -1; node *ptr_fast,*ptr_slow; ptr_fast = list; ptr_slow = list; while(ptr_fast->next && ptr_fast->next->next){ ptr_fast = ptr_fast->next->next; ptr_slow = ptr_slow->next; if(ptr_fast==ptr_slow){ isLoop = true; cout<<"It's Circular!"<<" Meeting at: "<<ptr_fast->value<<endl; break; } } if(!isLoop){ cout<<"It's not Circular!"<<endl; return -1; } //Find the length of circular int length = 0; while(ptr_fast->next && ptr_fast->next->next){ ptr_fast = ptr_fast->next->next; ptr_slow = ptr_slow->next; length++; if(ptr_fast==ptr_slow){ cout<<"The length: "<<length<<" Meeting at: "<<ptr_fast->value<<endl; break; } } //Find the starting node of circular ptr_fast = list; int len = 0; while(ptr_fast!=ptr_slow){ ptr_fast = ptr_fast->next; ptr_slow = ptr_slow->next; len++; } cout<<"Starting node: "<<ptr_fast->value<<endl; cout<<"lenght of link: "<<len+length<<endl; } int _tmain(int argc, _TCHAR* argv[]) { node *list = createCircularLinklist(circularNum); traverse(list); isCircular(list); return 0; }
相关文章推荐
- 判断单链表是否有环的相关问题
- 判断单链表是否有环相关问题(转载加总结)
- 判断单链表是否存在环,判断两个链表是否相交问题详解(转)
- 判断单链表是否存在环 判断两个链表是否相交问题
- 判断单链表是否存在环,判断两个链表是否相交问题详解
- 【转载】判断链表中是否有环 ----- 有关单链表中环的问题
- Q:判断链表中是否存在环的相关问题
- 判断单链表是否存在环,判断两个链表是否相交问题详解
- 判断链表中是否有环 ----- 有关单链表中环的问题
- 判断单链表是否存在环,判断两个链表是否相交问题详解(转载)
- 判断链表中是否有环 ----- 有关单链表中环的问题
- 数据结构与算法分析笔记与总结(java实现)--数组7:判断单链表是否相交问题构建乘积数组
- 判断单链表是否有环及确定环的入口结点问题
- 判断链表中是否有环 ----- 有关单链表中环的问题
- 判断单链表是否存在环,判断两个链表是否相交问题详解
- 判断链表中是否有环 -- 有关单链表中环的问题
- 笔面集锦:判断单链表里面是否有环及相关扩展题(转)
- 判断单链表是否存在环,判断两个链表是否相交问题详解
- 判断链表中是否有环 ----- 有关单链表中环的问题
- [zz]判断单链表是否存在环,判断两个链表是否相交问题详解