Code: Select all
; LCS_Get:
; Calculates the Longest Common Subsequence contained in *p_x and *p_y
; Works with any bytestring, not just for strings !
; So you might feed this function with e.g. binary filedata !
;
; Returns a pointer to resulting bytestring (+terminating 0, so IF you work with
; strings, you might just call PeekS(LCS_Get(...))
; The length is stored in the referenced *p_resLen, or set this parameter to 0,
; if you don't need to get the length.
;
; by Froggerprogger 04/08/12
ProcedureDLL.l LCS_Get(*p_x.l, p_xLen.l, *p_y.l, p_yLen.l, *p_resLen.l)
; LCS = Longest Common Subsequence
; based on pseudocode from Cormen's 'Introduction to Algorithms SE' p.353f
; (combination of LCS_LENGTH and (iterative) PRINT_LCS)
; by Froggerprogger 04/08/12
Protected i.l, j.l
Protected *mem.l
Protected resLen.l
Protected actPos.l
; define the arrays used for calculation (I wish we had local ones...)
Dim LCS_c.l(p_xLen, p_yLen)
Dim LCS_d.b(p_xLen, p_yLen) ; 1=upleft, 2=up, 3=left
; compute the main algorithm
For i=1 To p_xLen
For j = 1 To p_yLen
If PeekB(*p_x + (i-1)) = PeekB(*p_y + (j-1))
LCS_c(i, j) = LCS_c(i-1, j-1) + 1
LCS_d(i, j) = 1 ; upleft
Else
If LCS_c(i-1, j) >= LCS_c(i, j-1)
LCS_c(i,j) = LCS_c(i-1, j)
LCS_d(i,j) = 2 ; up
Else
LCS_c(i,j) = LCS_c(i, j-1)
LCS_d(i,j) = 3 ; left
EndIf
EndIf
Next j
Next i
; the length is stored in bottom right field
resLen = LCS_c(p_xLen, p_yLen)
; now we might free LCS_c
Dim LCS_c.l(0,0)
; allocate memory for our result (plus a terminating zero for comfortable use with PeekS)
*mem = AllocateMemory(resLen + 1)
If *mem = 0
ProcedureReturn -1
EndIf
i = p_xLen
j = p_yLen
actPos = resLen -1
; write out our lcs
While i > 0 And j > 0
If LCS_d(i,j) = 1
PokeB(*mem + actPos, PeekB(*p_x + (i-1)))
actPos - 1
i-1
j-1
ElseIf LCS_d(i,j) = 2
i-1
Else ; LCS_d(i,j) = 3
j-1
EndIf
Wend
; free LCS_d
Dim LCS_d.b(0,0)
; write the length of lcs at position *p_resLen
If *p_resLen
PokeL(*p_resLen, resLen)
EndIf
; return pointer to result
ProcedureReturn *mem
EndProcedure
a.s = "This is a string that contains some stupid stuff just to type something...!"
b.s = "This another one, that really (!) has nothing to do with spaghetti !"
len.l
Debug ".............................."
Debug "Longest Common Substring of the following 2 bytestrings:"
Debug ".............................."
Debug a
Debug b
Debug ".............................."
Debug PeekS(LCS_Get(@a, Len(a), @b, Len(b), @len))
Debug ".............................."
Debug "length: " + Str(len)