Java 生成大小为X的随机数的算法
在我的移动应用程序中,我必须为用户提供一个随机唯一的X字母数字代码,以便用户可以使用该字母数字代码进行回复以执行某些任务 将使用此应用程序的用户数量约为100万人,消息流量约为每天10万条消息 我只能使用26个大写字母、26个小写字母和10位数字。如果随机数大小为5,那么我可以生成916132832个唯一的组合。在组合用尽后,我想再次循环使用这个数字生成Java 生成大小为X的随机数的算法,java,algorithm,math,random,Java,Algorithm,Math,Random,在我的移动应用程序中,我必须为用户提供一个随机唯一的X字母数字代码,以便用户可以使用该字母数字代码进行回复以执行某些任务 将使用此应用程序的用户数量约为100万人,消息流量约为每天10万条消息 我只能使用26个大写字母、26个小写字母和10位数字。如果随机数大小为5,那么我可以生成916132832个唯一的组合。在组合用尽后,我想再次循环使用这个数字生成 我正在寻找一种算法方法。有什么算法可以解决这个问题吗?首先,为什么不使用 但如果您想自己生成数字,请尝试以下方法: 预先生成1000-2000
我正在寻找一种算法方法。有什么算法可以解决这个问题吗?首先,为什么不使用 但如果您想自己生成数字,请尝试以下方法: 预先生成1000-2000万个组合,并将它们保存在内存中的一组中。 当你想要下一个id时,从他们那里得到一个随机组合,并将其从集合中移除
当集合变为空时,使用原始组合重置集合(您可以保留原始集合的第二份副本以便快速重置)。如果您接受回收随机数,为什么要等待组合用尽后再回收
- 这使得数字在到达组合集末尾时越来越不随机
- 这迫使您维护一些数据库,以了解哪些数字已经被使用,哪些还没有被使用
- 生成所有组合并将它们放入数据库表中
- 将此表的大小存储在某个变量中
- 生成一个介于1和表大小之间的随机数R
- 获取存储在表第Rth行的组合
- 从表中删除Rth行,并减小size变量
- 当表为空(且大小变量为0)时,请重新启动
如果有足够的内存,也可以在内存中执行此操作。是否真的有可能耗尽所有代码?你说只有100万用户。如果我理解正确,这意味着你只需要生成一百万个代码。如果是这种情况,那么可能的代码(例如5个字符)的数量远远大于您需要的数量,解决方案很简单:只需不断为新用户生成随机代码,直到找到一个不需要的代码。您可以在哈希表中存储和查找使用过的代码。使用5个字符,您可以安全使用900天,然后必须重置 几周前,我为另一个StackOverflow用户编写了一些代码。这是一个随机生成器,它只生成新的数字
import java.util.BitSet;
import java.util.Random;
/**
* Random number generator without repeat in the given range at construction time.
*
* @author martijn
*/
public class NoRepeatRandom {
private Random random;
private BitSet used;
private int max;
/**
* Creates new instance of NoRepeatRandom, with the range <code>[0-max[</code>.
* @param max the maximum for the range
* @param seed the seed for the underlying {@link java.util.Random}
*/
public NoRepeatRandom(int max, long seed)
{
this.max = max;
this.used = new BitSet(max);
this.random = new Random(seed);
}
/**
* Creates new instance of NoRepeatRandom, with the range <code>[0-max[</code>.<br />
* <code>System.currentTimeMillis()</code> is used as seed for the underlying {@link java.util.Random}
* @param max the maximum for the range
*/
public NoRepeatRandom(int max)
{
this(max, System.currentTimeMillis());
}
/**
* Gives the next random number
* @return a new random number. When finished it returns -1.
*/
public int next()
{
if (isFinished())
{
return -1;
}
while (true)
{
int r = random.nextInt(max);
if (!used.get(r))
{
used.set(r);
return r;
}
}
}
/**
* Tells if the random generator has finished. Which means that all number in the range
* [0-max[ are used.
* @return true if all numbers are used, otherwise false.
*/
public boolean isFinished()
{
return max == used.cardinality();
}
/**
* Sets all the numbers in the range [0-max[ to unused. Which means that all the numbers
* can be reused.
*/
public void reset()
{
used.clear();
}
/**
*
* @return the maximum.
*/
public int getMax()
{
return max;
}
}
然后创建它的一个实例:
NoRepeatRandom nrr = new NoRepeatRandom(916132832);
要生成新代码,请使用:
int codeInt = nrr.next();
if (codeInt == -1)
{
// All the codes are used, need to reset the random generator!
}
String code = toCode(codeInt);
剩下的部分是设计toCode(int)
方法:
public static final String charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvw013456789";
public static String toCode(int i)
{
String code = "";
return code;
}
如果您不需要强大的安全性,那么一个简单的方法就是
T=62**n
使计数器x
从0
运行到T-1
,其中n
是要使用的字符数x
,然后使用(x*P)%T
的编码,其中P
是与T
的大数互质,%
是模运算符p
与T
的互质,可以保证映射(x*p)%T
是一个双射,因此在重用第一个代码之前将使用所有代码
因为存在k
,所以k*p=1(mod T)
,因此对于每个y
,数字x=(k*y)%T
是y的倒数,因为x*p=(k*y)*p=y*(k*p)=y*1=y(mod T)
所以变换x->(x*p)%T)
是满射的,因此也是内射的,因为这个空间是有限的
您也可以尝试使用一些更复杂的双射函数,例如,将T
限制为二次幂并使用位洗牌,但如果您确实需要安全性,则最好每次都使用随机码,可能是检查它是否最近未与队列和位表或哈希表一起使用,具体取决于两者中哪一个更小。您的代码可以是唯一的,也可以是算法生成的
我知道你们想到的算法是将序数映射成代码,每个数字有62个字符(A-Z,A-Z,0-9)。5个字符的代码实际上是一个5位数的基数62。生成适当范围内的随机数,并将其转换为基数62
为了避免重复,取一个足够大的数字范围,并将该范围洗牌。所有保证唯一且不以任何特定顺序排列。如果您正在寻找非常简单的东西,请尝试以下方法:
Date date = new Date();
String random = String.valueOf(date.getTime()).substring(6);
在不久的将来,这些数字永远不会重复 我能想到的最佳解决方案是保留每日更新的私钥。将按键与手机号码结合使用,生成一个5位代码,并将该代码存储在数据库中。更新私钥时,使代码无效并清除数据库。通过这种方式,您可以决定现有代码何时失效,而不是等待组合完成。这种方法可以灵活地将代码大小从5增加到任何其他大小,并且只存储已经使用过的值 实现这一点的最佳方法是使用一种称为或FPE的加密技巧。您的问题与FPE的问题非常相似。您的案例似乎最好通过使用生成FPE来解决。在你的特殊情况下