给定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;
但避免碰撞并不好
我以为我可以为row
和column
应用两次简单哈希方法,并将结果用作新坐标,但我不确定这是一个很好的解决方案。
有什么想法吗?
答案 0 :(得分: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+5
将p = 5+6*(s/6);
初始化为多个表单p
,6k+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)
考虑使用双哈希函数在矩阵内部获得更好的分布, 但鉴于你无法避免崩溃,我建议使用一系列哨兵 并标记您访问的位置,这样您就可以确保一次访问一个单元格。