如何实现一个随机数生成器,给定一个时间间隔(随机)生成该时间间隔内的所有数字,而不重复?
它应该消耗尽可能少的时间和内存。
刚刚发明的C#-ruby-ish伪代码中的示例:
interval = new Interval(0,9)
rg = new RandomGenerator(interval);
count = interval.Count // equals 10
count.times.do{
print rg.GetNext() + " "
}
这应输出如下内容:
1 4 3 2 7 5 0 9 8 6
答案 0 :(得分:13)
使用间隔填充数组,然后将其随机播放。
洗牌N个元素数组的标准方法是选择0到N-1之间的随机数(比如R),并用项目[N]交换项目[R]。然后从N中减去一个,并重复直到达到N = 1.
答案 1 :(得分:4)
答案 2 :(得分:1)
一个建议,但它是内存密集型的:
生成器构建一个区间中所有数字的列表,然后将其洗牌。
答案 3 :(得分:1)
偶尔对shuffle方法的有用替代方法是使用可订阅集合容器。在每个步骤中,选择随机数0< = n<计数。从集合中提取第n个项目。
主要问题是典型的容器无法有效处理。我已经将它用于位向量,但只有当最大可能成员相当小时,它才能正常工作,因为找到第n个设置位所需的位向量的线性扫描。
99%的时间,最好的方法是像其他人建议的那样洗牌。
修改强>
我错过了一个简单的数组是一个很好的“设置”数据结构的事实 - 不要问我为什么,我以前用过它。 “技巧”是你不关心数组中的项是否排序。在每个步骤中,您随机选择一个并提取它。要填充空槽(无需将平均一半的项目向下移动一步),只需将当前结束项目以恒定时间移动到空槽中,然后将数组大小减小一个。
例如......
class remaining_items_queue
{
private:
std::vector<int> m_Items;
public:
...
bool Extract (int &p_Item); // return false if items already exhausted
};
bool remaining_items_queue::Extract (int &p_Item)
{
if (m_Items.size () == 0) return false;
int l_Random = Random_Num (m_Items.size ());
// Random_Num written to give 0 <= result < parameter
p_Item = m_Items [l_Random];
m_Items [l_Random] = m_Items.back ();
m_Items.pop_back ();
}
技巧是获得一个随机数生成器,它给出(合理均匀分布)0到n-1范围内的数字,其中n每次都可能不同。大多数标准随机发生器给出固定范围。虽然以下不会给出均匀分布,但通常足够好......
int Random_Num (int p)
{
return (std::rand () % p);
}
std :: rand返回范围0&lt; = x&lt;的随机值RAND_MAX,其中RAND_MAX是实现定义的。
答案 4 :(得分:1)
一种非常有效的方法来混合每个索引唯一的数字数组来自图像处理,并在应用像像素溶解等技术时使用。
基本上,您从有序的2D数组开始,然后移动列和行。这些排列很容易实现,你甚至可以使用一个精确的方法,在n个排列之后产生x,y的结果值。
在3x3网格上描述的基本技术:
1)从有序列表开始,每个号码只能存在一次
0 1 2
3 4 5
6 7 8
2)选择要随机播放的行/列,将其前进一步。在这种情况下,我将第二行向右移动。
0 1 2
5 3 4
6 7 8
3)选择一个你想要随机播放的行/列...我将第二列填满一个。
0 7 2
5 1 4
6 3 8
4)选择...例如,第一行,左边一个。
2 0 7
5 1 4
6 3 8
您可以根据需要随时重复这些步骤。您也可以在一维数组上进行此类转换。所以你的结果现在是[2,0,7,5,1,4,6,3,8]。
答案 5 :(得分:0)
答案 6 :(得分:0)
一种方法是在您的示例中生成有序列表(0-9)。
然后使用随机函数从列表中选择一个项目。从原始列表中删除该项目并将其添加到新列表的尾部。
当原始列表为空时,该过程结束。
输出新列表。
答案 7 :(得分:0)
您可以使用linear congruential generator随机选择的参数,以便生成完整的句号。您需要小心,因为随机数的质量可能很差,具体取决于参数。