private static void BuildModificationData(ModificationData A, int startA, int endA, ModificationData B, int startB, int endB, int[] forwardDiagonal, int[] reverseDiagonal) { while (startA < endA && startB < endB && A.HashedPieces[startA].Equals(B.HashedPieces[startB])) { startA++; startB++; } while (startA < endA && startB < endB && A.HashedPieces[endA - 1].Equals(B.HashedPieces[endB - 1])) { endA--; endB--; } int aLength = endA - startA; int bLength = endB - startB; if (aLength > 0 && bLength > 0) { EditLengthResult res = CalculateEditLength(A.HashedPieces, startA, endA, B.HashedPieces, startB, endB, forwardDiagonal, reverseDiagonal); if (res.EditLength <= 0) { return; } if (res.LastEdit == Edit.DeleteRight && res.StartX - 1 > startA) { A.Modifications[--res.StartX] = true; } else if (res.LastEdit == Edit.InsertDown && res.StartY - 1 > startB) { B.Modifications[--res.StartY] = true; } else if (res.LastEdit == Edit.DeleteLeft && res.EndX < endA) { A.Modifications[res.EndX++] = true; } else if (res.LastEdit == Edit.InsertUp && res.EndY < endB) { B.Modifications[res.EndY++] = true; } BuildModificationData(A, startA, res.StartX, B, startB, res.StartY, forwardDiagonal, reverseDiagonal); BuildModificationData(A, res.EndX, endA, B, res.EndY, endB, forwardDiagonal, reverseDiagonal); } else if (aLength > 0) { for (int i = startA; i < endA; i++) { A.Modifications[i] = true; } } else if (bLength > 0) { for (int i = startB; i < endB; i++) { B.Modifications[i] = true; } } }
private static EditLengthResult CalculateEditLength(int[] A, int startA, int endA, int[] B, int startB, int endB, int[] forwardDiagonal, int[] reverseDiagonal) { if (null == A) { throw new ArgumentNullException("A"); } if (null == B) { throw new ArgumentNullException("B"); } if (A.Length == 0 && B.Length == 0) { return(new EditLengthResult()); } Edit lastEdit; int N = endA - startA; int M = endB - startB; int MAX = M + N + 1; int HALF = MAX / 2; int delta = N - M; bool deltaEven = delta % 2 == 0; forwardDiagonal[1 + HALF] = 0; reverseDiagonal[1 + HALF] = N + 1; for (int D = 0; D <= HALF; D++) { // forward D-path for (int k = -D; k <= D; k += 2) { int kIndex = k + HALF; int x, y; if (k == -D || (k != D && forwardDiagonal[kIndex - 1] < forwardDiagonal[kIndex + 1])) { x = forwardDiagonal[kIndex + 1]; // y up move down from previous diagonal lastEdit = Edit.InsertDown; } else { x = forwardDiagonal[kIndex - 1] + 1; // x up move right from previous diagonal lastEdit = Edit.DeleteRight; } y = x - k; int startX = x; int startY = y; while (x < N && y < M && A[x + startA] == B[y + startB]) { x += 1; y += 1; } forwardDiagonal[kIndex] = x; if (!deltaEven) { int revX, revY; if (k - delta >= (-D + 1) && k - delta <= (D - 1)) { int revKIndex = (k - delta) + HALF; revX = reverseDiagonal[revKIndex]; revY = revX - k; if (revX <= x && revY <= y) { var res = new EditLengthResult(); res.EditLength = 2 * D - 1; res.StartX = startX + startA; res.StartY = startY + startB; res.EndX = x + startA; res.EndY = y + startB; res.LastEdit = lastEdit; return(res); } } } } // reverse D-path for (int k = -D; k <= D; k += 2) { int kIndex = k + HALF; int x, y; if (k == -D || (k != D && reverseDiagonal[kIndex + 1] <= reverseDiagonal[kIndex - 1])) { x = reverseDiagonal[kIndex + 1] - 1; // move left from k+1 diagonal lastEdit = Edit.DeleteLeft; } else { x = reverseDiagonal[kIndex - 1]; //move up from k-1 diagonal lastEdit = Edit.InsertUp; } y = x - (k + delta); int endX = x; int endY = y; while (x > 0 && y > 0 && A[startA + x - 1] == B[startB + y - 1]) { x -= 1; y -= 1; } reverseDiagonal[kIndex] = x; if (deltaEven) { int forX, forY; if (k + delta >= -D && k + delta <= D) { int forKIndex = (k + delta) + HALF; forX = forwardDiagonal[forKIndex]; forY = forX - (k + delta); if (forX >= x && forY >= y) { var res = new EditLengthResult(); res.EditLength = 2 * D; res.StartX = x + startA; res.StartY = y + startB; res.EndX = endX + startA; res.EndY = endY + startB; res.LastEdit = lastEdit; return(res); } } } } } throw new Exception("Should never get here"); }