我今天遇到了一个有趣的问题,并在互联网上寻找解决方案,但没有发现任何问题。问题是:
用户创建一个帐户,并为他提供一个唯一的ID号,例如123,以表示他的帐户。当另一个用户创建一个帐户时,我可以将最近创建的ID号添加1并将其分配给他,124。但是,这并不能完全匿名每个人,因为他现在知道用户123在他之前注册了。这是一个非常小的问题,但在某些可能的情况下,这可能会导致更大的问题。
更好的解决方案是让ID随机但唯一,这样任何人都无法确定谁先出现。
要解决此问题,可以使用标准哈希函数或随机数生成器为每个人创建唯一ID,但之后会遇到冲突的可能性。这可以通过检查冲突并再次运行来避免,但是让我们说这个例子,这会使系统运行太慢。或者可能是生成器在不完整的信息上运行,无法检查是否存在冲突。
我提出的一个不同的想法是,基本上有一个洗牌的牌,你存储,并在你需要一个新的ID时取一个顶部。当你在牌组中用完牌时,你将在最后一张牌组中的最高牌处继续使用新牌组并将其重新洗牌。缺点是你必须存储这副牌,如果你不小心丢失了牌组,你会遇到很多问题,试图重新创建它或者在没有它的情况下继续存在。
这个问题的一个非常类似的解决方案是每次都根据固定的种子重新创建这个改组的牌组,并取出牌组的第n张牌而不是顶牌。这个问题是,每次你需要一张新卡时,这个套牌都会变得很贵。
我试图提出的其他数学模型都存在序列中下一个数字可预测的问题(每个数字与前一个数字相比是固定的数量)。他们中的很多人也有碰撞的问题。
所以我的问题是:是否有一些数学模型我可以插入数字来获取不需要使用存储在内存中的“deck”(读取:数组)或在每次函数调用时重新计算的唯一ID。 / p>
例如
randomID(number, seed, range)
randomID(1,123,1000) = 284
randomID(2,123,1000) = 739
randomId(3,123,1000) = 088
randomId(3,888,1000) = 912
我查了https://code.google.com/p/smhasher/wiki/MurmurHash3这似乎很有希望,但我不认为它适用于任意数字范围,只有32位或64位。
答案 0 :(得分:1)
不确定您将如何存储此内容,但您可以创建一个足以处理将使用您的网站的所有用户的大型数组。然后,您可以创建一个从随机第n个索引开始的随机数,并随机迭代一次。当你落在一个空的索引上时,你在该索引中放入一个值(例如1或其他),用户将得到索引的id。如果该索引已有值,则重复该过程,直到随机数落在索引上。关于这一点的好处是你甚至不必迭代,因为你可以只将随机数添加到当前索引。唯一的逻辑是某种mod函数来处理到达数组末尾的情况。希望这会有所帮助。
答案 1 :(得分:1)
您可以选择一个伪随机数生成器,其周期大于您需要支持的最大用户数,然后您只需要使用最后使用的值为PRNG播种,以生成下一个。如果您以某种方式忘记了上次使用的值,则可以使用初始种子,然后根据已注册用户的数量生成更多值。您可能希望避免使用过大值的PRNG(例如,如果您的用户数少于65536,则可能会找到16位一个2 ^ 16周期),因此这些数字是实用的。
答案 2 :(得分:1)
这是灵活高效的方法: -
- 维护哈希表。
- 选择一个与您需要使用的哈希表大小成比例的数字M.
- 为第一个M ID生成M个随机数,并通过哈希表查找防止冲突。
- 在M代结束时,如果它们未使用大小为M + 1的数组,则添加前M个id的所有id + 1值。
- 如果之前没有使用,请添加ID 0.
- 对于每个下一个id生成,随机从数组中选择一个id。
- 如果不在哈希表中,则添加id + 1。
醇>
优点: -
- 您可以使用M调节随机性和使用的存储空间。您的ID越高,M越随机。您可能会在使用的空间和随机性之间找到折衷方案。
- 您可以轻松地将内存数据库(如redis用于哈希表和数组)。
- 生成唯一ID的时间复杂度为O(1)
醇>
答案 3 :(得分:1)
您可以使用block cipher来实现此目的。当您加密块(固定位数)时,密码将其映射到具有相同位数的不同块。解密步骤撤消了这一点。没有两个不同的块被映射到同一个块。
因此,请将您的用户ID称为64位,并使用64位分组密码和密钥对其进行加密,并且您拥有随机用户ID。要获取原始用户ID,只需使用相同的密钥进行解密。