There is a one-way linked list. How can we determine whether the Chain List contains loops and how to locate the starting point of the loop in the linked list?
For the first question, we can find on the network that we use two pointers to traverse this one-way linked list. The first pointer is P1, one step at a time; the second pointer is P2, and two steps at a time; when the P2 pointer catches up with P1, it indicates that there is a loop in the linked list.
The most vivid metaphor for this solution is running in the playground, which will take the lap of the slow speed.
It can be proved that when P2 catches up with P1, P1 must have not completed the loop, and P2 will not catch up with it after Multiple Laps across P1.
We can prove from the gap between P2 and P1 that P2 will catch up with P1 but will not skip
Because P2 takes two steps at a time, and P1 takes one step, the gap between them is reduced step by step. When, 0, and 0, the gap will overlap.
Based on this method, it can be proved that P2 does not always speed up detection after taking more than three steps at a time, but may not identify loops.
For example, when the circumference l of the ring is an even number and the difference between P2 and P1 is odd, P2 will never overlap with P1 every three steps, because the gap between them is: 5, 3, 1, L-1, L-3
For the second question, how to find the entrance to the loop is the important content here:
The solution is as follows: when P2 follows two steps each, and P1 follows one step each, it is found that P2 and P1 overlap, and the one-way linked list has a loop.
Next, let P2 return to the head of the linked list and re-walk. Each step does not go 2, but 1. When P1 and P2 meet again, it is the entrance of the loop.
This can prove:
When P2 and P1 met for the first time, assuming that P1 took n steps and the loop entrance was completed during step P
Path of P1: P + c = N; C is the intersection of P1 and P2, and the distance from the loop entry
P2 path: P + C + K * l = 2 * n; L indicates the circumference of the loop, and K is an integer.
Obviously, if P1 takes n steps again from P + C, it can return to P + C.
At the same time, if P2 starts from the beginning, after N does not, it will reach P + C.
Obviously, in this step, P1 and P2 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.
The test code is as follows:
# Include "iostream. H"
# Include "memory. H"
# Include "New. H"
Class clist {
Public:
Int ndata;
Clist * pnext;
} * Proot = NULL;
Const int size = sizeof (clist)/sizeof (INT );
Int buffer [101 * size];
Bool Init (int n)
{
Proot = (clist *) buffer;
If (n <1 & n> 98) return false;
Clist * ptemp = NULL;
For (INT I = 0; I <101; I ++ ){
Ptemp = new (buffer + I * size) clist ();
Ptemp-> ndata = I;
Ptemp-> pnext = (clist *) (buffer + (I + 1) * size );
};
Ptemp-> pnext = (clist *) (buffer + N * size );
Return true;
}
Void rollback ircle (clist * proot)
{
Clist * P1, * P2;
P1 = P2 = proot;
Do {
P2 = P2-> pnext;
P1 = p1-> pnext;
} While (P2! = NULL & P1! = P2 );
If (p1 = P2 ){
P2 = proot;
While (1 ){
P2 = P2-> pnext;
If (P1-> pnext = P2) break;
P1 = p1-> pnext;
}
P1-> pnext = NULL;
}
}
Main ()
{
Clist * plist = proot;
If (Init (21 ))
{
Cout <"Before clear :! "<"/R/N ";
Plist = proot;
For (INT I = 0; I <104; I ++)
{
Cout <plist-> ndata <"/R/N ";
Plist = plist-> pnext;
}
Clearcircle (proot );
}
Cout <"after clear:" <"/R/N ";
Plist = proot;
While (plist ){
Cout <plist-> ndata <"/R/N ";
Plist = plist-> pnext;
}
Return 0;
}