散列函数来迭代矩阵

时间:2011-09-18 14:51:31

标签: objective-c c algorithm hash matrix

给定NxN矩阵和(row,column)位置,以随机(或伪随机)顺序选择不同位置的方法是什么,尽量避免碰撞?< / p>

例如:考虑一个5x5矩阵并从(1,2)

开始
0 0 0 0 0 
0 0 X 0 0 
0 0 0 0 0 
0 0 0 0 0 
0 0 0 0 0 

我正在寻找像

这样的方法
(x,y) hash (x,y);

跳转到矩阵中的不同位置,尽可能避免碰撞 (不关心如何返回两个不同的值,没关系,只想到一个数组)。

当然,我可以简单地使用

row = rand()%N;
column = rand()%N;

但避免碰撞并不好 我以为我可以为rowcolumn应用两次简单哈希方法,并将结果用作新坐标,但我不确定这是一个很好的解决方案。

有什么想法吗?

5 个答案:

答案 0 :(得分:3)

您可以在开始迭代之前确定步行的顺序吗?如果你的矩阵很大,这种方法不是节省空间的,但它很简单,没有碰撞。我会做类似的事情:

  1. 生成所有坐标的数组。从列表中删除起始位置。
  2. 随机播放列表(有Fisher-Yates shuffle here的示例代码)
  3. 使用随机播放列表作为步行订单。

答案 1 :(得分:2)

编辑2&amp; 3:模块化方法:给定s数组元素,选择prime p of form 2+3*n,p> s。对于i = 1到p,当该值在1 ... s-1范围内时,使用单元格(i i i)%p。 (对于行长度r,单元格#c下标为c%r,c / r。)

实际上,该方法使用H(i)=(i i i)mod p作为散列函数。 reference表示当i的范围从1到p时,H(i)取0到p-1中的每个值,每个值恰好一次。

例如,当s = 25且p = 29或47时,它按以下顺序使用单元格:

p=29: 1 8 6 9 13 24 19 4 14 17 22 18 11 7 12 3 15 10 5 16 20 23 2 21 0
p=47: 1 8 17 14 24 13 15 18 7 4 10 2 6 21 3 22 9 12 11 23 5 19 16 20 0

根据bc代码

s=25;p=29;for(i=1;i<=p;++i){t=(i^3)%p; if(t<s){print " ",t}}

上面的文字显示了我在答案的编辑2 中提出的建议。下面的文字显示了我的第一个答案。

编辑0 :(这是Seamus评论所适用的建议):以“随机出现”的方式浏览矢量的简单方法是重复添加d(d> 1)到索引。如果d和s是互质的(其中s =向量长度),这将访问所有元素。注意,下面我的例子是矢量;你可以在矩阵的另一个轴上独立地做同样的事情,除了下面提到的问题之外,它会有不同的增量。注意,“coprime”表示gcd(d,s)= 1。如果s是可变的,则需要gcd() code示例: Say s是10. gcd(s,x)对于{1,3,7,9}中的x是1而对于{2,4,5,6中的x不是1 8,10}。假设我们选择d = 7,并从i = 0开始。我将取值0,7,14,21,28,35,42,49,56,63,70,其中模数10是0,7,4,1,8,5,2,9,6,3 ,0。 编辑1&amp; 3:不幸的是,这会在双轴情况下出现问题;例如,如果对x轴使用d = 7,对于y轴使用e = 3,而前21次命中将是不同的,则它将继续重复相同的21次命中。为了解决这个问题,将整个矩阵视为向量,使用d与gcd(d,s)= 1,并将单元格数转换为上标的下标。

答案 2 :(得分:1)

如果你只想迭代矩阵,那么row ++有什么问题; if(row == N){row = 0;柱++}?

如果你独立地遍历行和列,并且每个循环在N步之后循环回到开头,那么(行,列)对将仅通过矩阵的N ^ 2个单元中的N个进行交互。

如果你想以伪随机顺序迭代矩阵的所有单元格,你可以在这里查看随机排列的问题。

答案 3 :(得分:1)

这是解决我之前回答的问题的伴随答案:如何在哈希函数中找到适当的素数p >= s(其中s =矩阵元素的数量){{ 1}}。

我们需要找到格式H(i) = (i*i*i) mod p的素数,其中3n+2是任何奇数,使得3 * n + 2&gt; = s。请注意,n odd给出n,其中k不必为奇数。在下面的示例代码中,3n+2 = 3(2k+1)+2 = 6k+5p = 5+6*(s/6);初始化为多个表单p6k+5以此格式维护p += 6;

下面的代码显示,六行代码足以进行计算。在代码之后显示时间,速度相当快:在s = 50万时12 us,在s = 5亿时200 us,其中我们表示微秒。

p

2.5GHz Athlon 5200 +的定时结果:

// timing how long to find primes of form 2+3*n by division
// jiw 20 Sep 2011
#include <stdlib.h>
#include <stdio.h>
#include <sys/time.h>
double ttime(double base) {
  struct timeval tod;
  gettimeofday(&tod, NULL);
  return tod.tv_sec + tod.tv_usec/1e6 - base;
}
int main(int argc, char *argv[]) {
  int d, s, p, par=0;
  double t0=ttime(0);
  ++par; s=5000;  if (argc > par) s = atoi(argv[par]);
  p = 5+6*(s/6);
  while (1) {
    for (d=3; d*d<p; d+=2)
      if (p%d==0) break;
    if (d*d >= p) break;
    p += 6;
  }
  printf ("p = %d after %.6f seconds\n", p, ttime(t0));
  return 0;
}

更新1 当然,时间不是确定的(即,根据qili ~/px > for i in 0 00 000 0000 00000 000000; do ./divide-timing 500$i; done p = 5003 after 0.000008 seconds p = 50021 after 0.000010 seconds p = 500009 after 0.000012 seconds p = 5000081 after 0.000031 seconds p = 50000021 after 0.000072 seconds p = 500000003 after 0.000200 seconds qili ~/px > factor 5003 50021 500009 5000081 50000021 500000003 5003: 5003 50021: 50021 500009: 500009 5000081: 5000081 50000021: 50000021 500000003: 500000003 的值,机器上的其他进程等,可能会有很大的不同;例如:

s

答案 4 :(得分:0)

考虑使用双哈希函数在矩阵内部获得更好的分布, 但鉴于你无法避免崩溃,我建议使用一系列哨兵 并标记您访问的位置,这样您就可以确保一次访问一个单元格。