【发布时间】:2011-12-07 03:08:45
【问题描述】:
假设文件 A 有字节:
2
5
8
0
33
90
1
3
200
201
23
12
55
我有一个简单的散列算法,我存储最后三个连续字节的总和,所以:
2
5
8 - = 8+5+2 = 15
0
33
90 - = 90+33+0 = 123
1
3
200 - = 204
201
23
12 - = 236
所以我可以将文件 A 表示为 15, 123, 204, 236
假设我将该文件复制到新计算机 B 并进行了一些小修改,文件 B 的字节为:
255
2
5
8
0
33
90
1
3
200
201
23
12
255
255
“注意区别是文件开头多出一个字节,结尾多出两个字节,但其余部分非常相似”
所以我可以执行相同的算法来确定文件的某些部分是否相同。请记住,文件 A 由哈希码 15, 123, 204, 236 表示,让我们看看文件 B 是否给了我一些哈希码!
在文件 B 上,我必须每 3 个连续字节执行一次
int[] sums; // array where we will hold the sum of the last bytes
255 sums[0] = 255
2 sums[1] = 2+ sums[0] = 257
5 sums[2] = 5+ sums[1] = 262
8 sums[3] = 8+ sums[2] = 270 hash = sums[3]-sums[0] = 15 --> MATHES FILE A!
0 sums[4] = 0+ sums[3] = 270 hash = sums[4]-sums[1] = 13
33 sums[5] = 33+ sums[4] = 303 hash = sums[5]-sums[2] = 41
90 sums[6] = 90+ sums[5] = 393 hash = sums[6]-sums[3] = 123 --> MATHES FILE A!
1 sums[7] = 1+ sums[6] = 394 hash = sums[7]-sums[4] = 124
3 sums[8] = 3+ sums[7] = 397 hash = sums[8]-sums[5] = 94
200 sums[9] = 200+ sums[8] = 597 hash = sums[9]-sums[6] = 204 --> MATHES FILE A!
201 sums[10] = 201+ sums[9] = 798 hash = sums[10]-sums[7] = 404
23 sums[11] = 23+ sums[10] = 821 hash = sums[11]-sums[8] = 424
12 sums[12] = 12+ sums[11] = 833 hash = sums[12]-sums[9] = 236 --> MATHES FILE A!
55 sums[13] = 55+ sums[12] = 888 hash = sums[13]-sums[10] = 90
255 sums[14] = 255+ sums[13] = 1143 hash = sums[14]-sums[11] = 322
255 sums[15] = 255+ sums[14] = 1398 hash = sums[15]-sums[12] = 565
所以通过查看该表,我知道文件 B 包含文件 A 中的字节加上其他字节,因为哈希码匹配。
我展示这个算法的原因是因为它是 n 阶的,换句话说,我能够计算最后 3 个连续字节的哈希值,而无需遍历它们!
如果我在哪里有一个更复杂的算法,例如对最后 3 个字节执行 md5,那么它将是 n^3 的顺序,因为当我遍历文件 B 时,我必须有一个内部 for 循环来计算最后三个字节的哈希。
所以我的问题是:
如何改进算法,使其保持 n 阶。那就是只计算一次哈希。如果我使用现有的散列算法,例如 md5,我将不得不在算法内部放置一个内部循环,这将显着增加算法的顺序。
请注意,可以用乘法而不是加法来做同样的事情。但计数器显着增长非常快。也许我可以把乘法和加法和减法结合起来......
编辑
如果我用谷歌搜索:
递归散列函数 in-grams
出现了很多信息,我认为那些算法很难理解......
我必须为一个项目实现这个算法,这就是我重新发明轮子的原因......我知道那里有很多算法。
另外一个我认为的替代解决方案是执行相同的算法加上另一个强大的算法。所以在文件 A 上,我将每 3 个字节加上每 3 个字节的 md5 执行相同的算法。在第二个文件上,如果第一个算法成真,我将只执行第二个算法....
【问题讨论】:
-
听起来你在重塑
rsync。 en.wikipedia.org/wiki/Rolling_hash 可能会感兴趣。 -
是的,不幸的是,我需要重新发明轮子......我需要为我学校的数据结构课做这个......
-
为什么这个订单是
n!?我看到订单n*m,其中n是文件中的行数,m是您加在一起的先前值的数量。如果n==m,那么你所有的总和都是一样的,这将毫无价值,但仍然是n^2。如果您使用 dequeue,则可以使用此命令n,当您推送一个新值时将一个值添加到当前总和,并在您弹出一个值时从当前总和中减去一个值。 -
我打算使用!作为感叹对不起谢谢我会解决它。
-
你有实现递归的约束吗?使用非递归实现会更快。
标签: c# algorithm filecompare