【问题标题】:Checksum for an integer array?整数数组的校验和?
【发布时间】:2012-06-05 06:13:55
【问题描述】:

我有一个大小为 4、9、16 或 25(根据输入)的数组,数组中的数字相同但减一(如果数组大小为 9,则数组中的最大元素数组将是 8) 数字以 0 开头 我想做一些算法来为数组生成某种校验和,这样我就可以比较两个数组是否相等,而无需遍历整个数组并逐个检查每个元素。

我在哪里可以获得此类信息?我需要一些尽可能简单的东西。谢谢。

编辑:只是为了清楚我想要什么:

-数组中的所有数字都是不同的,所以[0,1,1,2]无效,因为存在重复元素(1)

-数字的位置很重要,所以[0,1,2,3]和[3,2,1,0]不一样

-该数组将包含数字0,因此也应考虑到这一点。

编辑:

好的,我尝试在这里实现 Fletcher 算法: http://en.wikipedia.org/wiki/Fletcher%27s_checksum#Straightforward

int fletcher(int array[], int size){
  int i;
  int sum1=0;
  int sum2=0;
  for(i=0;i<size;i++){
    sum1=(sum1+array[i])%255;
    sum2=(sum2+sum1)%255;
  }
  return (sum2 << 8) | sum1;
}

说实话,我不知道返回线是做什么的,但不幸的是,该算法不起作用。 对于数组 [2,1,3,0] 和 [1,3,2,0] 我得到相同的校验和。

EDIT2:

好的,这是另一个,阿德勒校验和 http://en.wikipedia.org/wiki/Adler-32#Example_implementation

#define MOD 65521;

unsigned long adler(int array[], int size){
  int i;
  unsigned long a=1;
  unsigned long b=0;
  for(i=0;i<size;i++){
    a=(a+array[i])%MOD;
    b=(b+a)%MOD;
  }
  return (b <<16) | a;
}

这也行不通。 数组 [2,0,3,1] 和 [1,3,0,2] 生成相同的校验和。 我在这里失去了希望,有什么想法吗?

【问题讨论】:

  • 数组中的数字不是唯一的,我猜?!那么 { 1,2,2,4 } 是否有效?
  • > 数组中的数字是一样的 你能详细说明一下吗?
  • 哦,对不起,我没有提到!是的,这些数字是唯一的,因此 [1,2,2,4] 无效。
  • {1,2,3,4} 和 {4,3,2,1}。根据您的定义,这两个数组是否相等?
  • 不,这些是不同的。

标签: arrays algorithm compare checksum


【解决方案1】:

让我们以您的 25 个整数数组为例。您解释说它可以包含唯一整数 0 到 24 的任何排列。根据this page,有 25! (25 个阶乘)可能的排列,即 15511210043330985984000000。远远超过 32 位整数可以包含的内容。

结论是,无论你怎么努力,都会有碰撞。

现在,这是一个考虑位置的简单算法:

int checksum(int[] array, int size) {
  int c = 0;
  for(int i = 0; i < size; i++) {
    c += array[i];
    c = c << 3 | c >> (32 - 3); // rotate a little
    c ^= 0xFFFFFFFF; // invert just for fun
  }
  return c;
}

【讨论】:

  • 我不同意碰撞不可避免的说法。 @UmNyobe 的解决方案虽然对于这种特殊情况不够有效,但可以保证 0% 的冲突。说某事非常困难与说某事不可能完全不同:)
  • 很抱歉,这也不起作用;我正在测试的 12 个数组中有 7 个生成相同的校验和。
  • @PavanManjunath 我不是说这很难,我说这是不可能的。你不能有 15511210043330985984000000 个不同的 32 位整数,所以你不能对每个可能的数组都有一个唯一的校验和,所以你发生冲突。
  • 根据@UmNyobe 使用索引作为校验和的解决方案,您的程序中不需要有 15511210043330985984000000 个不同的 32 位整数。您只需要计算用户希望比较的 2 个数组的索引。这些指数可以达到 15511210043330985984000000 ,我同意。所以我们只需要 2 个变量来保存这么大的值。另请注意,最初 OP 开始时没有任何语言偏好。所以 Java 的 BigInteger 类可以帮助保存这个大整数。简而言之,这并非不可能!
  • @PavanManjunath 虽然它不再是校验和,但它是一种独特的签名。顺便说一句,BigInteger 数据存储在一个数组中。所以要比较两个“校验和”,你最终会比较两个数组。等一下!这不是我们一开始就想避免的吗? ;D
【解决方案2】:

我认为您想要的是以下线程的答案:

Fast permutation -> number -> permutation mapping algorithms

您只需将排列映射到的数字作为校验和。由于每个排列只有一个校验和,因此不可能有更小的无冲突校验和。

【讨论】:

  • 替换,例如,将 25 元素数组的比较与大约 12 个字节的比较 - 一个胜利,一旦你摊销了计算 数字 的成本(空间是没有问题,因为数组是等效的并且更大)。根据大量检查的相等校验和值的概率,快速和小校验和可能会更慢。例如,对于每个排列的可能性相同,预计它会更快。
【解决方案3】:

加权和的校验和怎么样?让我们以 [0,1,2,3] 为例。首先选择种子和限制,我们选择种子为7,限制为10000007。

a[4] = {0, 1, 2, 3}
limit = 10000007, seed = 7
result = 0
result = ((result + a[0]) * seed) % limit = ((0 + 0) * 7)) % 10000007 = 0
result = ((result + a[1]) * seed) % limit = ((0 + 1) * 7)) % 10000007 = 7
result = ((result + a[2]) * seed) % limit = ((7 + 2) * 7)) % 10000007 = 63
result = ((result + a[3]) * seed) % limit = ((63 + 3) * 7)) % 10000007 = 462

对于 [0, 1, 2, 3],您的校验和是 462。 参考是http://www.codeabbey.com/index/wiki/checksum

【讨论】:

    【解决方案4】:

    对于从 1 到 N 的 N 个唯一整数的数组,只需将元素相加将始终为 N*(N+1)/2。因此,唯一的区别在于排序。如果通过“校验和”暗示您可以容忍一些冲突,那么一种方法是将连续数字之间的差异相加。例如,{1,2,3,4} 的 delta 校验和是 1+1+1=3,但 {4,3,2,1} 的 delta 校验和是 -1+-1+-1= -3.

    没有对碰撞率或计算复杂度给出要求,但如果以上不适合,那么我推荐position dependent checksum

    【讨论】:

    • 不错且简单的逻辑,但它很容易出错 - {4,2,3,1} 也产生-3的校验和
    • {3,2,1,4} 是 1+1+3 = 5 & {3,1,2,4} 是 2+1+2 = 5。两者结果相同。那么,这将如何运作?
    • 对不起,我忘了说数字0也会在数组中。
    • 对,这就是我提到“碰撞”的原因。校验和通常有它们。好的校验和几乎没有冲突并且计算成本低。但是如果你想保证没有冲突,那么你必须遍历数组中的每个元素。
    • 没有对碰撞率或计算复杂性给出要求,但如果我的答案不适合,那么我建议使用与位置相关的校验和,如下所述:en.wikipedia.org/wiki/Checksum#Position-dependent_checksums
    【解决方案5】:

    据我了解,您的数组包含从 0 到 N-1 的数字排列。一种有用的校验和是数组在其字典顺序中的排名。这是什么意思 ?给定0, 1, 2 你有可能的排列

      1: 0, 1, 2
      2: 0, 2, 1
      3: 1, 0, 2
      4: 1, 2, 0
      5: 2, 0, 1
      6: 2, 1, 0
    

    校验和将是第一个数字,并在您创建数组时计算。

    中提出了解决方案

    Find the index of a given permutation in the list of permutations in lexicographic order

    这可能会有所帮助,尽管最好的算法似乎具有二次复杂度。要将其提高到线性复杂度,您应该事先缓存阶乘的值。

    优势?零碰撞。

    编辑:计算 该值类似于多项式的评估,其中阶乘用于单项式而不是幂。所以函数是

    f(x0,....,xn-1) = X0 * (0!) + X1 * (1!) + X2 * (2!) +...+ Xn-1 * (n-1!)
    

    这个想法是使用每个值来获得排列的子范围,并通过足够的值来确定唯一的排列。

    现在进行实现(如多项式之一):

    1. 预计算 0!.... 到 n-1!在程序开始时
    2. 每次设置数组时,都使用 f(elements) 来计算其校验和
    3. 您使用此校验和在 O(1) 中进行比较

    【讨论】:

    • 感谢您的回答!你能解释一下计算是什么吗?我似乎无法了解其他线程上的内容。
    • 虽然使用索引作为校验和的想法是一个很好的想法(0% 冲突),但是计算校验和的复杂性,阶乘的计算等无法击败简单的array1[i] == array2[i] O( n) 比较。
    • 我做错了什么或者这不起作用:数组 [0,1,2,3] 和 [2,1,0,3] 都生成 18 的校验和。跨度>
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-20
    • 1970-01-01
    • 2021-11-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多