There are several solutions to determine whether a linked list has a ring:
1. In a traversal table, a node that has been traversed is placed in a hash table. If a node already exists in a hash table, a ring exists. Time: O (n) Space: O (N)
2. Reverse the linked list. Time O (N), Space O (1), use three pointers. (Ref: http://www.cppblog.com/tx7do/archive/2009/01/06/71280.html)
Single-chain table reversal: Two possible implementations are provided below.
Normal version:
Void reverse (node * & head) {If (Head = 0) | (Head-> next = 0) return; // Edge Detection node * pnext = 0; node * pprev = head; // Save the node * pcur = head-> next; // get the current node while (pcur! = 0) {pnext = pcur-> next; // save the next node pcur-> next = pprev; // set the next node of the current node to the previous node pprev = pcur; // Save the current node as the previous node pcur = pnext; // set the current node to the next node} head-> next = NULL; head = pprev ;}
Recursive version:
Node * reverse (node * pnode, node * & head) {If (pnode = 0) | (pnode-> next = 0 )) // recursive jump condition {head = pnode; // cut the linked list; otherwise, a return pnode will be formed;} node * temp = reserve (pnode-> next, head ); // recursion temp-> next = pnode; // set the next node to the current node, both the front node return pnode; // return to the current node}
The inverted linked list method is used to reverse the pointer of each node. If a ring exists, the next pointer is reversed and the link is finally directed to the head of the linked list. If no ring exists, the next pointer will destroy the structure of the linked list (reverse the linked list). To restore the linked list, you need to reverse the linked list again. The spatial complexity of this method is O (1). In fact, we use three additional pointers, while the time complexity is O (n ), we can traverse the entire linked list at most two times (when there is no ring in the linked list ). The following is an implementation, but the biggest problem is:If a ring exists, it cannot be restored to the original state of the linked list..
bool reverse(Node *head) { Node *curr = head; Node *next = head->next; curr->next = NULL; while(next!=NULL) { if(next == head) { /* go back to the head of the list, so there is a loop */ next->next = curr; return true; } Node *temp = curr; curr = next; next = next->next; curr->next = temp; } /* at the end of list, so there is no loop, let's reverse the list back */ next = curr->next; curr ->next = NULL; while(next!=NULL) { Node *temp = curr; curr = next; next = next->next; curr->next = temp; } return false; }
3. Speed pointer. Time O (N), Space O (1), using two pointers. (Ref: http://blog.csdn.net/mingming_bupt/article/details/6331333)
Judge the existence of a ring: Set two pointers (fast and slow). The initial values are directed to the header. Slow moves one step forward each time, and fast moves two steps forward each time. If the linked list has a ring, fast must first enter the ring, and slow enters the ring, and the two pointers must meet. (Of course, if the first line to the end of fast is null, it is a non-circular linked list ).
bool IsExitsLoop(slist * head){slist * slow = head , * fast = head;while ( fast && fast -> next ){slow = slow -> next;fast = fast -> next -> next;if ( slow == fast ) break ;}return ! (fast == NULL || fast -> next == NULL);}
Search for the entry point of the ring: When fast is followed by two steps and slow is followed by one step, it is found that fast and slow overlap, and the one-way linked list has a loop. Next, let fast return to the head of the linked list and go again. Step 1 each time. When fast and slow meet again, it is the entrance of the loop.
Proof: When fast and slow met for the first time, assuming that slow took n steps, the loop entry was in step P, then
Slow path: P + c = N; C indicates the distance between the intersection of fast and slow to the loop entry.
Fast path: P + C + K * l = 2 * n; L indicates the circumference of the loop, and K is an integer.
Obviously, if slow takes another n steps from P + C, it can return to P + C.
At the same time, fast starts from scratch. The step size is 1. After n steps, it will reach P + C.
Obviously, in this process, fast and slow only follow different paths in the previous P step. So when P1 and P2 overlap again, it must be at the loop entry point of the linked list.
slist * FindLoopPort(slist * head){slist * slow = head, * fast = head;while ( fast && fast -> next ){slow = slow -> next;fast = fast -> next -> next;if ( slow == fast ) break ;}if (fast == NULL || fast -> next == NULL)return NULL;slow = head;while (slow != fast){slow = slow -> next;fast = fast -> next;}return slow;}