差分算法错误地交换36和35

时间:2016-08-06 04:34:46

标签: java arrays algorithm diff

我已经为此工作了大约3个小时,根本无法弄清楚世界上有什么不对。我试图写一个简单的"差异"算法,给定两个字节数组,输出一个单字节数组,描述两者之间的差异。我设法写了一个相当简单的算法,但是围绕字节有一些奇怪的行为" 35"和" 36。"我确定我的代码中某处有一些错误,但我一遍又一遍地仔细检查它,而且我自己也找不到它。因此,我将我的代码提交给大众,希望能够发现我不断错过的任何错误。

该代码旨在接受两个输入ab并生成一些输出c,这样可以重建a给定b和{{} 1}}以及给定cb的{​​{1}}的重建。对于更多情况,这是我目前未能尝试解决PPGC上的this挑战。

我尝试做的是使用通用格式a汇编字节数组 字节数组也可以压缩,但我已经验证了它的工作情况。我还验证了索引已正确读取,测试用例已正确加载,并且eof和分隔符正常工作。

守则:

c

其他细节:

在重建<<index><<a-byte><b-byte>...><separator>...><eof-indicator><0 if b, 1 if b><remaining bytes of a or b>时,算法始终用package com.gmail.socraticphoenix.sandbox; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.URL; import java.util.AbstractMap; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; public class Diffs { public static final byte ESCAPE = 1; public static final byte SEPARATOR = 2; public static final byte EOF = 3; public static void main(String[] args) throws IOException { int totalLength = 0; System.out.println("Reading files..."); Map<byte[], byte[]> tests = Diffs.getTests(); System.out.println("Finished reading, beginning diff generation."); for (Map.Entry<byte[], byte[]> pair : tests.entrySet()) { byte[] a = pair.getKey(); byte[] b = pair.getValue(); byte[] diff = Diffs.generateDiff(a, b); totalLength += diff.length; byte[] reconA = Diffs.reverseA(b, diff); byte[] reconB = Diffs.reverseB(a, diff); boolean succesful = true; if (!Arrays.equals(a, reconA)) { System.out.println("Failed to reconstruct a."); for (int i = 0; i < Math.min(a.length, reconA.length); i++) { System.out.print(a[i]); if (a[i] != reconA[i]) { System.out.print("^"); } else { System.out.print(" "); } } System.out.println(); for (int i = 0; i < Math.min(a.length, reconA.length); i++) { System.out.print(reconA[i]); if (a[i] != reconA[i]) { System.out.print("^"); } else { System.out.print(" "); } } if (a.length != reconA.length) { System.out.println(); System.out.print("Different lengths"); } System.out.println(); System.out.println(); succesful = false; } if (!Arrays.equals(b, reconB)) { System.out.println("Failed to reconstruct b."); for (int i = 0; i < Math.min(b.length, reconB.length); i++) { System.out.print(b[i]); if (b[i] != reconB[i]) { System.out.print("^"); } else { System.out.print(" "); } } System.out.println(); for (int i = 0; i < Math.min(b.length, reconB.length); i++) { System.out.print(reconB[i]); if (b[i] != reconB[i]) { System.out.print("^"); } else { System.out.print(" "); } } if (b.length != reconB.length) { System.out.println(); System.out.print("Different lengths"); } System.out.println(); System.out.println(); succesful = false; } if (!succesful) { break; } } System.out.println("Finished diff generation."); System.out.println("Final Length: " + totalLength); } public static byte[] generateDiff(byte[] a, byte[] b) throws IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(); DataOutputStream dataOut = new DataOutputStream(out); boolean cp = false; ByteArrayOutputStream outc = new ByteArrayOutputStream(); int i; for (i = 0; i < Math.min(a.length, b.length); i++) { byte ab = a[i]; byte bb = b[i]; if (ab != bb) { outc.write(ab); outc.write(bb); cp = true; } else { if (cp) { byte[] result = outc.toByteArray(); outc = new ByteArrayOutputStream(); dataOut.writeInt(i); for (byte z : result) { if (z == Diffs.SEPARATOR || z == Diffs.ESCAPE || z == Diffs.EOF) { dataOut.write(Diffs.ESCAPE); } dataOut.write(z); } dataOut.write(Diffs.SEPARATOR); } cp = false; } } byte[] result = outc.toByteArray(); outc = new ByteArrayOutputStream(); if (result.length != 0) { dataOut.writeInt(i); for (byte z : result) { if (z == Diffs.SEPARATOR || z == Diffs.ESCAPE || z == Diffs.EOF) { dataOut.write(Diffs.ESCAPE); } dataOut.write(z); } dataOut.write(Diffs.SEPARATOR); } byte[] remaining; dataOut.write(Diffs.EOF); if (a.length < b.length) { dataOut.write(0); remaining = b; } else if (b.length < a.length) { dataOut.write(1); remaining = a; } else { remaining = new byte[0]; } for (byte g : remaining) { dataOut.write(g); } dataOut.flush(); byte[] finalResult = out.toByteArray(); byte[] compressed = Diffs.compress(finalResult); if (compressed.length < finalResult.length) { outc.write(1); outc.write(compressed); } else { outc.write(0); outc.write(finalResult); } return outc.toByteArray(); } public static byte[] reverseA(byte[] arrayB, byte[] diff) throws IOException { byte compressed = diff[0]; byte[] actualDiff = new byte[diff.length - 1]; System.arraycopy(diff, 1, actualDiff, 0, diff.length - 1); if (compressed == 1) { actualDiff = Diffs.decompress(actualDiff); } DataInputStream in = new DataInputStream(new ByteArrayInputStream(actualDiff)); ByteArrayOutputStream out = new ByteArrayOutputStream(); int current = 0; while (true) { in.mark(70); byte a = in.readByte(); if (a == Diffs.EOF) { break; } in.reset(); Map.Entry<Integer, byte[]> entry = Diffs.fetchNextChunk(in); int index = entry.getKey(); byte[] vals = entry.getValue(); int i; for (i = 0; i < index; i++) { if (current + i < arrayB.length) { out.write(arrayB[current + i]); } else { break; } } current += i + (vals.length / 2); for (int j = 0; j < vals.length; j++) { if (j % 2 != 0) { out.write(vals[j]); } } } int decider = in.read(); if (decider == 1) { int i; while ((i = in.read()) > -1) { out.write(i); } } return out.toByteArray(); } public static byte[] reverseB(byte[] arrayA, byte[] diff) throws IOException { byte compressed = diff[0]; byte[] actualDiff = new byte[diff.length - 1]; System.arraycopy(diff, 1, actualDiff, 0, diff.length - 1); if (compressed == 1) { actualDiff = Diffs.decompress(actualDiff); } DataInputStream in = new DataInputStream(new ByteArrayInputStream(actualDiff)); ByteArrayOutputStream out = new ByteArrayOutputStream(); int current = 0; while (true) { in.mark(70); byte a = in.readByte(); if (a == Diffs.EOF) { break; } in.reset(); Map.Entry<Integer, byte[]> entry = Diffs.fetchNextChunk(in); int index = entry.getKey(); byte[] vals = entry.getValue(); int i; for (i = 0; i < index; i++) { if (current + i < arrayA.length) { out.write(arrayA[current + i]); } else { break; } } current += i + (vals.length / 2); for (int j = 0; j < vals.length; j++) { if (j % 2 == 0) { out.write(vals[j]); } } } int decider = in.read(); if (decider == 0) { int i; while ((i = in.read()) > -1) { out.write(i); } } return out.toByteArray(); } public static Map.Entry<Integer, byte[]> fetchNextChunk(DataInputStream stream) throws IOException { int i = stream.readInt(); ByteArrayOutputStream out = new ByteArrayOutputStream(); boolean escape = false; int z; while ((z = stream.readByte()) > -1) { if (z == Diffs.ESCAPE && !escape) { escape = true; } else { if (escape) { out.write(z); } else { if (z == Diffs.SEPARATOR) { break; } } escape = false; } } return new AbstractMap.SimpleEntry<>(i, out.toByteArray()); } public static byte[] compress(byte[] bytes) throws IOException { ByteArrayOutputStream stream = new ByteArrayOutputStream(bytes.length); GZIPOutputStream gzipOutputStream = new GZIPOutputStream(stream); gzipOutputStream.write(bytes); gzipOutputStream.close(); stream.close(); return stream.toByteArray(); } public static byte[] decompress(byte[] bytes) throws IOException { ByteArrayInputStream stream = new ByteArrayInputStream(bytes); GZIPInputStream gzipInputStream = new GZIPInputStream(stream); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); int res = 0; byte[] buf = new byte[1024]; while (res >= 0) { res = gzipInputStream.read(buf, 0, buf.length); if (res > 0) { outputStream.write(buf, 0, res); } } stream.close(); gzipInputStream.close(); outputStream.close(); return outputStream.toByteArray(); } public static Map<byte[], byte[]> getTests() throws IOException { String target = "https://gist.githubusercontent.com/nathanmerrill/125a6e2ae7d9ded3531fedff036cf74b/raw/7a578393826014a788b424fd9558cc14c3f8908e/commits.txt"; URL url = new URL(target); Map<byte[], byte[]> tests = new HashMap<>(); for (String s : Diffs.readLines(url)) { String[] pieces = s.split(" "); tests.put(Diffs.readBytes(new URL(pieces[0])), Diffs.readBytes(new URL(pieces[1]))); } return tests; } public static byte[] readBytes(URL url) throws IOException { InputStream stream = url.openStream(); ByteArrayOutputStream out = new ByteArrayOutputStream(); int i; while ((i = stream.read()) > -1) { out.write(i); } return out.toByteArray(); } public static List<String> readLines(URL url) throws IOException { BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream())); List<String> lines = new ArrayList<>(); String line; while ((line = reader.readLine()) != null) { lines.add(line); } return lines; } } 替换序列36 32,并在重构35 32时用a替换序列35 32

更具体地说,上述程序的输出是:

36 32

请注意,更改的字节后面紧跟b

感谢您的帮助!

0 个答案:

没有答案