我试图生成1到20,000之间的10,000个唯一随机整数以存储在BST中,但是不确定这样做的最佳方法。
我看到了一些关于如何使用数组或向量的好的建议,但没有关于BST的建议。我有一个contains
方法,但是我不认为它会在这种情况下起作用,因为它用于搜索并返回有关查找所需数字的尝试次数的结果。以下是我得到的最接近的,但是不喜欢我的==
运算符。使用数组并将其仅存储在BST中会更好吗?还是有更好的方法使用下面的代码,以便在生成数字的同时将它们直接存储在树中?
for (int i = 0; i < 10000; i++)
{
int random = rand() % 20000;
tree1Ptr->add(random);
for (int j = 0; j < i; j++) {
if (tree1Ptr[j]==random) i--;
}
}
答案 0 :(得分:1)
您的代码中有几个问题。但是,让我们直接进入痛点。
主要问题是什么?
根据您的代码,很明显tree1Ptr
是一个指针。原则上,它应指向树的一个节点,该节点具有两个指针,一个指向左侧节点,另一个指向右侧节点。
因此,在代码中的某处,您应该具有:
tree1Ptr = new Node; // or whatever the type of your node is called
但是,在您的内部循环中,您只是像在使用数组一样使用它:
for (int i = 0; i < 10000; i++)
{
int random = rand() % 20000;
tree1Ptr->add(random);
for (int j = 0; j < i; j++) {
if (tree1Ptr[j]==random) //<============ OUCH !!
i--;
}
}
编译器不会抱怨,因为它是有效的语法:您可以在指针上使用数组索引。但是,您有责任确保自己不超出范围(因此,j保持<1)。
其他评论
顺便说一句,在内部循环中,您只想说如果找到该号码就必须重试。如果已经找到编号,则可以break
进行内部循环,以免继续。
您还应该为随机数生成器设置种子,以避免始终以相同的顺序运行程序。
如何解决?
您确实需要加深对BST的了解。遍历该节点需要与当前节点中的值进行比较,并根据结果,使用左指针或右指针继续迭代,而不使用索引。但是在这里解释太久了。因此,也许您应该寻找一个教程,例如this one
答案 1 :(得分:0)
对于许多唯一的“随机”数字,我通常使用Format Preserving Encryption。由于加密是一对一的,因此只要输入是唯一的,就可以保证获得唯一的输出。不同的加密密钥将生成不同的输出集,即输入的不同排列。只需对0、1、2、3、4,...进行加密,就可以保证输出是唯一的。
您希望数字在[1 .. 20,000]范围内。不幸的是,20,000个需要21位,大多数加密方案具有偶数个位:在您的情况下为22位。这意味着您将需要骑自行车散步。如果数字太大,请重新加密输出,直到获得期望范围内的数字为止。由于您的输入最多只能达到10,000,而您将要循环行走到20,000以上,因此您仍将避免重复。
我知道的唯一允许22位块大小的标准密码是Hasty Pudding密码。另外,编写您自己的简单Feistel cipher也很容易。如果您不希望使用密码安全性,那么四轮就足够了。为了获得加密级别的安全性,您将需要使用NIST批准的AES / FFX。
答案 2 :(得分:0)
您可以通过两种方式不从序列中随机选择唯一的数字,而不用对先前选择的数字(即BST中已经存在的数字)进行检查。
一种简单的方法是对1 ... 20,000的排序数组进行洗牌,然后仅选择前10,000个项目:
#include <algorithm>
#include <vector>
std::vector<int> values(20000);
for (int i = 0; i < 20000; ++i) {
values[i] = i+1;
}
std::random_shuffle(values.begin(), values.end());
for (int i = 0; i < 10000; ++i) {
// Insert values[i] into your BST
}
如果要选择的随机数(10,000)的大小与总数(20,000)的大小可比,则此方法效果很好,因为随机改组的复杂性将在较大的结果集上摊销。
如果要选择的随机数的大小远小于总数的大小,则可以使用另一种方法:
#include <chrono>
#include <random>
#include <vector>
// Use timed seed so every run produces different random picks.
std::default_random_engine reng(
std::chrono::steady_clock::now().time_since_epoch().count());
int num_pick = 1000; // # of random numbers remained to pick
int num_total = 20000; // Total # of numbers to pick from
int cur_value = 1; // Current prospective number to be picked
while (num_pick > 0) {
// Probability to pick `cur_value` is num_pick / (num_total-cur_value+1)
std::uniform_int_distribution<int> distrib(0, num_total-cur_value);
if (distrib(reng) < num_pick) {
bst.insert(cur_value); // insert `cur_value` to your BST
--num_pick;
}
++cur_value;
}