private void GetMatchPoints(SubArray A, SubArray B, ArrayList MatchPoints) { if (A.Length > 0 && B.Length > 0) { //Find the middle snake from (x,y) to (u,v) int x, u, k; int D = FindMiddleSnake(A, B, out x, out u, out k); int y = x - k; int v = u - k; if (D > 1) { GetMatchPoints(new SubArray(A, 1, x), new SubArray(B, 1, y), MatchPoints); for (int i = x + 1; i <= u; i++) { //Output absolute X and Y (not relative to the current subarray) MatchPoints.Add(new Point(i + A.Offset, i - k + B.Offset)); } GetMatchPoints(new SubArray(A, u + 1, A.Length - u), new SubArray(B, v + 1, B.Length - v), MatchPoints); } else { //If there are no differences, we have to output all of the points. //If there's only one difference, we have to output all of the //match points, skipping the single point that is different. Debug.Assert(D == 0 || Math.Abs(A.Length - B.Length) == 1, "A and B's lengths must differ by 1 if D == 1"); //Only go to the minimum of the two lengths since that's the //most that can possibly match between the two subsequences. int N = A.Length; int M = B.Length; if (M > N) { //Output A[1..N] as match points int iCurrY = 1; for (int i = 1; i <= N; i++) { //We must skip the one difference when we hit it if (A[i] != B[iCurrY]) { iCurrY++; } MatchPoints.Add(new Point(i + A.Offset, iCurrY + B.Offset)); iCurrY++; } } else { //Output B[1..M] as match points int iCurrX = 1; for (int i = 1; i <= M; i++) { //We must skip the one difference when we hit it if (A[iCurrX] != B[i]) { iCurrX++; } MatchPoints.Add(new Point(iCurrX + A.Offset, i + B.Offset)); iCurrX++; } } } } }
private int FindMiddleSnake(SubArray A, SubArray B, out int iPathStartX, out int iPathEndX, out int iPathK) { //We don't have to check the result of this because the calling procedure //has already check the length preconditions. SetupFictitiousPoints(A, B); iPathStartX = -1; iPathEndX = -1; iPathK = 0; int iDelta = A.Length - B.Length; int iCeiling = (int)Math.Ceiling((A.Length + B.Length) / 2.0); for (int D = 0; D <= iCeiling; D++) { for (int k = -D; k <= D; k += 2) { //Find the end of the furthest reaching forward D-path in diagonal k. GetForwardDPaths(A, B, D, k); //If iDelta is odd (i.e. remainder == 1 or -1) and ... if ((iDelta % 2 != 0) && (k >= (iDelta - (D - 1)) && k <= (iDelta + (D - 1)))) { //If the path overlaps the furthest reaching reverse (D-1)-path in diagonal k. if (m_vecForward[k] >= m_vecReverse[k]) { //The last snake of the forward path is the middle snake. iPathK = k; iPathEndX = m_vecForward[k]; iPathStartX = iPathEndX; int iPathStartY = iPathStartX - iPathK; while (iPathStartX > 0 && iPathStartY > 0 && A[iPathStartX] == B[iPathStartY]) { iPathStartX--; iPathStartY--; } //Length of an SES is 2D-1. return(2 * D - 1); } } } for (int k = -D; k <= D; k += 2) { //Find the end of the furthest reaching reverse D=path in diagonal k+iDelta GetReverseDPaths(A, B, D, k, iDelta); //If iDelta is even and ... if ((iDelta % 2 == 0) && ((k + iDelta) >= -D && (k + iDelta) <= D)) { //If the path overlaps the furthest reaching forward D-path in diagonal k+iDelta. if (m_vecReverse[k + iDelta] <= m_vecForward[k + iDelta]) { //The last snake of the reverse path is the middle snake. iPathK = k + iDelta; iPathStartX = m_vecReverse[iPathK]; iPathEndX = iPathStartX; int iPathEndY = iPathEndX - iPathK; while (iPathEndX < A.Length && iPathEndY < B.Length && A[iPathEndX + 1] == B[iPathEndY + 1]) { iPathEndX++; iPathEndY++; } //Length of an SES is 2D. return(2 * D); } } } } //We should never get here if the algorithm is coded correctly. Debug.Assert(false); return(-1); }