The basic idea is to put the line numbers of text A as columns ("x") and the lines of text B as rows ("y"). Now you try to find the shortest "edit path" from the upper left corner to the lower right corner, where you can always go horizontally or vertically, but diagonally from (x,y) to (x+1,y+1) only if line x in text A is identical to line y in text B.
Myers' fundamental concept is the "furthest reaching D-path on diagonal k": a D-path is an edit path starting at the upper left corner and containing exactly D non-diagonal elements ("differences"). The furthest reaching D-path on diagonal k is the one that contains the most (diagonal) elements which ends on diagonal k (where k = y - x).
Example:
H E L L O W O R L D ____ L \___ O \___ W \________
Since every D-path has exactly D horizontal or vertical elements, it can only end on the diagonals -D, -D+2, ..., D-2, D.
Since every furthest reaching D-path contains at least one furthest reaching (D-1)-path (except for D=0), we can construct them recursively.
Since we are really interested in the shortest edit path, we can start looking for a 0-path, then a 1-path, and so on, until we find a path that ends in the lower right corner.
To save space, we do not need to store all paths (which has quadratic space requirements), but generate the D-paths simultaneously from both sides. When the ends meet, we will have found "the middle" of the path. From the end points of that diagonal part, we can generate the rest recursively.
This only requires linear space.
The overall (runtime) complexity is:
O(N * D^2 + 2 * N/2 * (D/2)^2 + 4 * N/4 * (D/4)^2 + ...)
= O(N * D^2 * 5 / 4) = O(N * D^2),
(With each step, we have to find the middle parts of twice as many regions as before, but the regions (as well as the D) are halved.)
So the overall runtime complexity stays the same with linear space, albeit with a larger constant factor.
| Modifier and Type | Class and Description |
|---|---|
| pack-priv class | MyersDiff.
A class to help bisecting the sequences a and b to find minimal edit paths. |
| Modifier and Type | Field and Description |
|---|---|
| protected HashedSequence | a
The first text to be compared. |
| protected HashedSequence | b
The second text to be compared. |
| protected HashedSequenceComparator | cmp
Comparison function for sequences. |
| protected EditList | edits
The list of edits found during the last call to
|
| public static final DiffAlgorithm | INSTANCE
Singleton instance of MyersDiff. |
| pack-priv MyersDiff |
| Access | Constructor and Description |
|---|---|
| private | MyersDiff(EditList edits, HashedSequenceComparator<S> cmp, HashedSequence<S> a, HashedSequence<S> b, Edit region)
|
| Modifier and Type | Method and Description |
|---|---|
| private void | calculateEdits(Edit
portion of the sequences to examine. r)Entrypoint into the algorithm this class is all about. |
| protected void | calculateEdits(int
start of the part of A which should be compared
(0<=beginA<sizeof(A)) beginA, int end of the part of A which should be compared
(beginA<=endA<sizeof(A)) endA, int start of the part of B which should be compared
(0<=beginB<sizeof(B)) beginB, int end of the part of B which should be compared
(beginB<=endB<sizeof(B)) endB)Calculates the differences between a given part of A against another given part of B |
| private static PrintWriter | |
| public static void |
| a | back to summary |
|---|---|
| protected HashedSequence<S> a The first text to be compared. Referred to as "Text A" in the comments | |
| b | back to summary |
|---|---|
| protected HashedSequence<S> b The second text to be compared. Referred to as "Text B" in the comments | |
| cmp | back to summary |
|---|---|
| protected HashedSequenceComparator<S> cmp Comparison function for sequences. | |
| edits | back to summary |
|---|---|
| protected EditList edits The list of edits found during the last call to
| |
| INSTANCE | back to summary |
|---|---|
| public static final DiffAlgorithm INSTANCE Singleton instance of MyersDiff. | |
| middle | back to summary |
|---|---|
| pack-priv MyersDiff<S>. | |
| MyersDiff | back to summary |
|---|---|
| private MyersDiff(EditList edits, HashedSequenceComparator<S> cmp, HashedSequence<S> a, HashedSequence<S> b, Edit region) | |
| calculateEdits | back to summary |
|---|---|
| private void calculateEdits(Edit r) Entrypoint into the algorithm this class is all about. This method triggers that the differences between A and B are calculated in form of a list of edits.
| |
| calculateEdits | back to summary |
|---|---|
| protected void calculateEdits(int beginA, int endA, int beginB, int endB) Calculates the differences between a given part of A against another given part of B
| |
| err | back to summary |
|---|---|
| private static PrintWriter err() | |
| main | back to summary |
|---|---|
| public static void main(String[] args) Main method
| |
| Modifier and Type | Class and Description |
|---|---|
| pack-priv class | |
| pack-priv abstract class | |
| pack-priv class |
| Modifier and Type | Field and Description |
|---|---|
| pack-priv MyersDiff | |
| protected int | |
| protected int | |
| protected Edit | |
| protected int | |
| protected int | |
| pack-priv MyersDiff |
| Access | Constructor and Description |
|---|---|
| pack-priv |
| Modifier and Type | Method and Description |
|---|---|
| pack-priv Edit | |
| pack-priv void |
| backward | back to summary |
|---|---|
| pack-priv MyersDiff<S>. | |
| beginA | back to summary |
|---|---|
| protected int beginA | |
| beginB | back to summary |
|---|---|
| protected int beginB | |
| edit | back to summary |
|---|---|
| protected Edit edit | |
| endA | back to summary |
|---|---|
| protected int endA | |
| endB | back to summary |
|---|---|
| protected int endB | |
| forward | back to summary |
|---|---|
| pack-priv MyersDiff<S>. | |
| MiddleEdit | back to summary |
|---|---|
| pack-priv MiddleEdit() | |
| calculate | back to summary |
|---|---|
| pack-priv Edit calculate(int beginA, int endA, int beginB, int endB) | |
| initialize | back to summary |
|---|---|
| pack-priv void initialize(int beginA, int endA, int beginB, int endB) | |
| Access | Constructor and Description |
|---|---|
| pack-priv |
| Modifier and Type | Method and Description |
|---|---|
| pack-priv final void | adjustMinMaxK(int k, int x)
Implements abstract org.
|
| pack-priv final int | |
| pack-priv final int | |
| pack-priv final boolean | isBetter(int left, int right)
Implements abstract org.
|
| pack-priv final boolean | meets(int d, int k, int x, long snake)
Implements abstract org.
|
| pack-priv final int |
| BackwardEditPaths | back to summary |
|---|---|
| pack-priv BackwardEditPaths() | |
| adjustMinMaxK | back to summary |
|---|---|
| pack-priv final void adjustMinMaxK(int k, int x) Implements abstract org.
| |
| getLeft | back to summary |
|---|---|
| pack-priv final int getLeft(int x) Implements abstract org.
| |
| getRight | back to summary |
|---|---|
| pack-priv final int getRight(int x) Implements abstract org.
| |
| isBetter | back to summary |
|---|---|
| pack-priv final boolean isBetter(int left, int right) Implements abstract org.
| |
| meets | back to summary |
|---|---|
| pack-priv final boolean meets(int d, int k, int x, long snake) Implements abstract org.
| |
| snake | back to summary |
|---|---|
| pack-priv final int snake(int k, int x) Implements abstract org.
| |
| Modifier and Type | Field and Description |
|---|---|
| pack-priv int | |
| pack-priv int | |
| pack-priv int | |
| pack-priv int | |
| pack-priv int | |
| pack-priv int | |
| pack-priv int | |
| private LongList | |
| private IntList |
| Access | Constructor and Description |
|---|---|
| pack-priv |
| Modifier and Type | Method and Description |
|---|---|
| pack-priv abstract void | |
| pack-priv boolean | |
| private int | |
| pack-priv final int | |
| pack-priv abstract int | |
| pack-priv abstract int | |
| pack-priv final long | |
| pack-priv final int | |
| pack-priv void | |
| pack-priv abstract boolean | |
| pack-priv final boolean | |
| pack-priv abstract boolean | |
| pack-priv final long | |
| pack-priv abstract int | |
| pack-priv final int | |
| pack-priv final int |
| beginK | back to summary |
|---|---|
| pack-priv int beginK | |
| endK | back to summary |
|---|---|
| pack-priv int endK | |
| maxK | back to summary |
|---|---|
| pack-priv int maxK | |
| middleK | back to summary |
|---|---|
| pack-priv int middleK | |
| minK | back to summary |
|---|---|
| pack-priv int minK | |
| prevBeginK | back to summary |
|---|---|
| pack-priv int prevBeginK | |
| prevEndK | back to summary |
|---|---|
| pack-priv int prevEndK | |
| snake | back to summary |
|---|---|
| private LongList snake | |
| x | back to summary |
|---|---|
| private IntList x | |
| EditPaths | back to summary |
|---|---|
| pack-priv EditPaths() | |
| adjustMinMaxK | back to summary |
|---|---|
| pack-priv abstract void adjustMinMaxK(int k, int x) | |
| calculate | back to summary |
|---|---|
| pack-priv boolean calculate(int d) | |
| forceKIntoRange | back to summary |
|---|---|
| private int forceKIntoRange(int k) | |
| getIndex | back to summary |
|---|---|
| pack-priv final int getIndex(int d, int k) | |
| getLeft | back to summary |
|---|---|
| pack-priv abstract int getLeft(int x) | |
| getRight | back to summary |
|---|---|
| pack-priv abstract int getRight(int x) | |
| getSnake | back to summary |
|---|---|
| pack-priv final long getSnake(int d, int k) | |
| getX | back to summary |
|---|---|
| pack-priv final int getX(int d, int k) | |
| initialize | back to summary |
|---|---|
| pack-priv void initialize(int k, int x, int minK, int maxK) | |
| isBetter | back to summary |
|---|---|
| pack-priv abstract boolean isBetter(int left, int right) | |
| makeEdit | back to summary |
|---|---|
| pack-priv final boolean makeEdit(long snake1, long snake2) | |
| meets | back to summary |
|---|---|
| pack-priv abstract boolean meets(int d, int k, int x, long snake) | |
| newSnake | back to summary |
|---|---|
| pack-priv final long newSnake(int k, int x) | |
| snake | back to summary |
|---|---|
| pack-priv abstract int snake(int k, int x) | |
| snake2x | back to summary |
|---|---|
| pack-priv final int snake2x(long snake) | |
| snake2y | back to summary |
|---|---|
| pack-priv final int snake2y(long snake) | |
| Access | Constructor and Description |
|---|---|
| pack-priv |
| Modifier and Type | Method and Description |
|---|---|
| pack-priv final void | adjustMinMaxK(int k, int x)
Implements abstract org.
|
| pack-priv final int | |
| pack-priv final int | |
| pack-priv final boolean | isBetter(int left, int right)
Implements abstract org.
|
| pack-priv final boolean | meets(int d, int k, int x, long snake)
Implements abstract org.
|
| pack-priv final int |
| ForwardEditPaths | back to summary |
|---|---|
| pack-priv ForwardEditPaths() | |
| adjustMinMaxK | back to summary |
|---|---|
| pack-priv final void adjustMinMaxK(int k, int x) Implements abstract org.
| |
| getLeft | back to summary |
|---|---|
| pack-priv final int getLeft(int x) Implements abstract org.
| |
| getRight | back to summary |
|---|---|
| pack-priv final int getRight(int x) Implements abstract org.
| |
| isBetter | back to summary |
|---|---|
| pack-priv final boolean isBetter(int left, int right) Implements abstract org.
| |
| meets | back to summary |
|---|---|
| pack-priv final boolean meets(int d, int k, int x, long snake) Implements abstract org.
| |
| snake | back to summary |
|---|---|
| pack-priv final int snake(int k, int x) Implements abstract org.
| |