Java 生成大小为X的随机数的算法

Java 生成大小为X的随机数的算法,java,algorithm,math,random,Java,Algorithm,Math,Random,在我的移动应用程序中,我必须为用户提供一个随机唯一的X字母数字代码,以便用户可以使用该字母数字代码进行回复以执行某些任务 将使用此应用程序的用户数量约为100万人,消息流量约为每天10万条消息 我只能使用26个大写字母、26个小写字母和10位数字。如果随机数大小为5,那么我可以生成916132832个唯一的组合。在组合用尽后,我想再次循环使用这个数字生成 我正在寻找一种算法方法。有什么算法可以解决这个问题吗?首先,为什么不使用 但如果您想自己生成数字,请尝试以下方法: 预先生成1000-2000

在我的移动应用程序中,我必须为用户提供一个随机唯一的X字母数字代码,以便用户可以使用该字母数字代码进行回复以执行某些任务

将使用此应用程序的用户数量约为100万人,消息流量约为每天10万条消息

我只能使用26个大写字母、26个小写字母和10位数字。如果随机数大小为5,那么我可以生成916132832个唯一的组合。在组合用尽后,我想再次循环使用这个数字生成


我正在寻找一种算法方法。有什么算法可以解决这个问题吗?

首先,为什么不使用

但如果您想自己生成数字,请尝试以下方法:

预先生成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来解决。在你的特殊情况下