V[ 1 ] = 0;
for ( int d = 0 ; d <= N + M ; d++ )
{
for ( int k = -d ; k <= d ; k += 2 )
{
// down or right?
bool down = ( k == -d || ( k != d && V[ k - 1 ] < V[ k + 1 ] ) );
int kPrev = down ? k + 1 : k - 1;
// start point
int xStart = V[ kPrev ];
int yStart = xStart - kPrev;
// mid point
int xMid = down ? xStart : xStart + 1;
int yMid = xMid - k;
// end point
int xEnd = xMid;
int yEnd = yMid;
// follow diagonal
int snake = 0;
while ( xEnd < N && yEnd < M && A[ xEnd ] == B[ yEnd ] ) { xEnd++; yEnd++; snake++; }
// save end point
V[ k ] = xEnd;
// check for solution
if ( xEnd >= N && yEnd >= M ) /* solution has been found */
}
}
List<int[]> Vs; // saved V's indexed on d
List<Snake> snakes; // list to hold solution
Point p = new Point(n, n); // start at the end
for ( int d = vs.Count - 1 ; p.X > 0 || p.Y > 0 ; d-- )
{
int[] V = Vs[d];
int k = p.X - p.Y;
// end point is in V
int xEnd = V[k];
int yEnd = x - k;
// down or right?
bool down = ( k == -d || ( k != d && V[ k - 1 ] < V[ k + 1 ] ) );
int kPrev = down ? k + 1 : k - 1;
// start point
int xStart = V[ kPrev ];
int yStart = xStart - kPrev;
// mid point
int xMid = down ? xStart : xStart + 1;
int yMid = xMid - k;
snakes.Insert( 0, new Snake( /* start, mid and end points */ ) );
p.X = xStart;
p.Y = yStart;
}
Investigating Myers' diff algorithm: Part 1 of 2文章是用C#写的,我这里将它简单改写称为Java。
为什么这里会倒着来遍历,也就是说,为什么从最后一条snake遍历到第一条snake呢?最后一条snake肯定是我们想要的有效路径的必经之路,所以倒着来寻找snake,肯定是找到的snake都是在有效路径上,因为Vs数组里面还有其他情况下的snake。
private void findMatchingItems() {
int posOld = mOldListSize;
int posNew = mNewListSize;
// traverse the matrix from right bottom to 0,0.
for (int i = mSnakes.size() - 1; i >= 0; i--) {
final Snake snake = mSnakes.get(i);
final int endX = snake.x + snake.size;
final int endY = snake.y + snake.size;
if (mDetectMoves) {
while (posOld > endX) {
// this is a removal. Check remaining snakes to see if this was added before
findAddition(posOld, posNew, i);
posOld--;
}
while (posNew > endY) {
// this is an addition. Check remaining snakes to see if this was removed
// before
findRemoval(posOld, posNew, i);
posNew--;
}
}
for (int j = 0; j < snake.size; j++) {
// matching items. Check if it is changed or not
final int oldItemPos = snake.x + j;
final int newItemPos = snake.y + j;
final boolean theSame = mCallback
.areContentsTheSame(oldItemPos, newItemPos);
final int changeFlag = theSame ? FLAG_NOT_CHANGED : FLAG_CHANGED;
mOldItemStatuses[oldItemPos] = (newItemPos << FLAG_OFFSET) | changeFlag;
mNewItemStatuses[newItemPos] = (oldItemPos << FLAG_OFFSET) | changeFlag;
}
posOld = snake.x;
posNew = snake.y;
}
}
public void dispatchUpdatesTo(ListUpdateCallback updateCallback) {
final BatchingListUpdateCallback batchingCallback;
if (updateCallback instanceof BatchingListUpdateCallback) {
batchingCallback = (BatchingListUpdateCallback) updateCallback;
} else {
batchingCallback = new BatchingListUpdateCallback(updateCallback);
// replace updateCallback with a batching callback and override references to
// updateCallback so that we don't call it directly by mistake
//noinspection UnusedAssignment
updateCallback = batchingCallback;
}
// These are add/remove ops that are converted to moves. We track their positions until
// their respective update operations are processed.
final List<PostponedUpdate> postponedUpdates = new ArrayList<>();
int posOld = mOldListSize;
int posNew = mNewListSize;
for (int snakeIndex = mSnakes.size() - 1; snakeIndex >= 0; snakeIndex--) {
final Snake snake = mSnakes.get(snakeIndex);
final int snakeSize = snake.size;
final int endX = snake.x + snakeSize;
final int endY = snake.y + snakeSize;
if (endX < posOld) {
dispatchRemovals(postponedUpdates, batchingCallback, endX, posOld - endX, endX);
}
if (endY < posNew) {
dispatchAdditions(postponedUpdates, batchingCallback, endX, posNew - endY,
endY);
}
for (int i = snakeSize - 1; i >= 0; i--) {
if ((mOldItemStatuses[snake.x + i] & FLAG_MASK) == FLAG_CHANGED) {
batchingCallback.onChanged(snake.x + i, 1,
mCallback.getChangePayload(snake.x + i, snake.y + i));
}
}
posOld = snake.x;
posNew = snake.y;
}
batchingCallback.dispatchLastEvent();
}