# Region KMP generic
Private Static int [] Next (ilist <t> pattern)
{
Int [] Next = new int [pattern. Count];
Next [0] =-1;
If (pattern. Count <2) // It is more efficient if only one element does not use KMP.
{
Return next;
}
Next [1] = 0; // The backtracking function value of the second element must be 0, which proves that:
// The pre-sequence set of 1 is {empty set, L [0]}, and the length of L [0] is not less than 1, so it is eliminated. The length of the empty set is 0, therefore, the value of the Backtracking function is 0.
Int I = 2; // the index of the character whose next value is being calculated
Int J = 0; // The intermediate variable required to calculate the next value. At the beginning of each iteration, J is always next [I-1].
While (I <pattern. Count) // it is obvious that when I = pattern. length, the next value of all characters has been calculated and the task has been completed.
{// Status
// Use equals as the element matching condition
If (pattern [I-1]. Equals (pattern [J]) // you must first remember that in the implementation of this function, the next value of iterative calculation starts from the third element.
{// If l [I-1] is equal to L [J], next [I] = J + 1
Next [I ++] = ++ J;
}
Else
{// If not equal, check the next possible value of next [I] ---- next [J]
J = next [J];
If (j =-1) // If J =-1, the value of next [I] is 1.
{// This part can be extracted and combined with the outer judgment
// The KMP in the book Code A difficult reason to understand is that it has been optimized to obscure its actual logic.
Next [I ++] = ++ J;
}
}
}
Return next;
}
Public static int executekmp (ienumerable <t> source, ilist <t> pattern)
{
Int [] Next = next (pattern );
Return executekmpinternal (source, pattern, next );
}
Private Static int executekmpinternal (ienumerable <t> source, ilist <t> pattern, int [] Next)
{
Ienumerator <t> iterator = source. getenumerator ();
Int I = iterator. movenext ()? 0:-1; // the two statements must always be executed together. // The master string pointer
Int J = 0; // mode string pointer
// If the child string does not match and the master string does not search
While (j <pattern. Count & I>-1)
{
If (iterator. current. equals (pattern [J]) // The logical meaning of I and j is embodied in this, used to indicate whether to determine whether the primary and mode strings are equal in this iteration
{
I = iterator. movenext ()? I + 1:-1;
J ++;
}
Else
{
J = next [J]; // iterative Backtracking Based on the indication
If (j =-1) // There is a situation with backtracing. This is the second case.
{
I = iterator. movenext ()? I + 1:-1;
J ++;
}
}
}
// If J = pattern. length, it indicates that the loop exit is because the child string has been matched but not the master string has been exhausted.
Return j <pattern. Count? -1: I-J;
}
/// <Summary>
/// The next function of the generic version
/// </Summary>
/// <Param name = "pattern"> A pattern string can be an object that implements ilist. All arrays implement ilist. </param>
/// <Param name = "isequal"> This function must reflect an equivalent relation, that is, it must meet the requirements of self-inversion, transfer, and exchange. Otherwise Algorithm A logical error occurs. This is the premise of the KMP algorithm. </Param>
/// <Returns> returns the next backtracking function </returns>
Private Static int [] Next (ilist <t> pattern, func <t, t, bool> isequal)
{
Int [] Next = new int [pattern. Count];
Next [0] =-1;
If (pattern. Count <2) // It is more efficient if only one element does not use KMP.
{
Return next;
}
Next [1] = 0; // The backtracking function value of the second element must be 0, which proves that:
// The pre-sequence set of 1 is {empty set, L [0]}, and the length of L [0] is not less than 1, so it is eliminated. The length of the empty set is 0, therefore, the value of the Backtracking function is 0.
Int I = 2; // the index of the character whose next value is being calculated
Int J = 0; // The intermediate variable required to calculate the next value. At the beginning of each iteration, J is always next [I-1].
While (I <pattern. Count) // it is obvious that when I = pattern. length, the next value of all characters has been calculated and the task has been completed.
{// Status
// Use equals as the element matching condition
If (isequal (pattern [I-1], pattern [J]) // you must first remember that in the implementation of this function, the next value of iterative calculation starts from the third element.
{// If l [I-1] is equal to L [J], next [I] = J + 1
Next [I ++] = ++ J;
}
Else
{// If not equal, check the next possible value of next [I] ---- next [J]
J = next [J];
If (j =-1) // If J =-1, the value of next [I] is 1.
{// This part can be extracted and combined with the outer judgment
// One of the reasons why KMP code in the book is hard to understand is that it has been optimized to obscure its actual logic.
Next [I ++] = ++ J;
}
}
}
Return next;
}
Public static int executekmp (ienumerable <t> source, ilist <t> pattern, func <t, t, bool> isequal)
{
Int [] Next = next (pattern, isequal );
Return executekmpinternal (source, pattern, isequal, next );
}
Private Static int executekmpinternal (ienumerable <t> source, ilist <t> pattern, func <t, t, bool> isequal, int [] Next)
{
Ienumerator <t> iterator = source. getenumerator ();
Int I = iterator. movenext ()? 0:-1; // the two statements must always be executed together. // The master string pointer
Int J = 0; // mode string pointer
// If the child string does not match and the master string does not search
While (j <pattern. Count & I>-1)
{
If (isequal (iterator. current, pattern [J]) // The logic meaning of I and j is embodied in this, used to indicate whether to determine whether the primary and mode strings are equal in this iteration
{
I = iterator. movenext ()? I + 1:-1;
J ++;
}
Else
{
J = next [J]; // iterative Backtracking Based on the indication
If (j =-1) // There is a situation with backtracing. This is the second case.
{
I = iterator. movenext ()? I + 1:-1;
J ++;
}
}
}
// If J = pattern. length, it indicates that the loop exit is because the child string has been matched but not the master string has been exhausted.
Return j <pattern. Count? -1: I-J;
}
Private Static int [] nextval (ilist <t> pattern)
{
Int [] Next = new int [pattern. Count];
Next [0] =-1;
If (pattern. Count <2) // It is more efficient if only one element does not use KMP.
{
Return next;
}
Next [1] = 0; // The backtracking function value of the second element must be 0, which proves that:
// The pre-sequence set of 1 is {empty set, L [0]}, and the length of L [0] is not less than 1, so it is eliminated. The length of the empty set is 0, therefore, the value of the Backtracking function is 0.
Int I = 2; // the index of the character whose next value is being calculated
Int J = 0; // The intermediate variable required to calculate the next value. At the beginning of each iteration, J is always next [I-1].
While (I <pattern. Count) // it is obvious that when I = pattern. length, the next value of all characters has been calculated and the task has been completed.
{// Status
// Use equals as the element matching condition
If (j =-1 | pattern [I-1]. equals (pattern [J]) // you must first remember that in this function implementation, the next value of iterative calculation starts from the third element.
{// If l [I-1] is equal to L [J], next [I] = J + 1
J ++;
If (pattern [I]. Equals (pattern [J])
{
Next [I] = next [J];
}
Else
{
Next [I] = J;
}
I ++;
}
Else
{// If not equal, check the next possible value of next [I] ---- next [J]
J = next [J];
}
}
Return next;
}
Public static int executekmpp (ienumerable <t> source, ilist <t> pattern)
{
Int [] Next = nextval (pattern );
Return executekmpinternal (source, pattern, next );
}
# Endregion
The test just now seems to be okay.