C ++如何生成10,000个UNIQUE随机整数以存储在BST中?

时间:2019-03-24 19:37:45

标签: c++ random binary-search-tree unique random-seed

我试图生成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--;
        }
    }

3 个答案:

答案 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中已经存在的数字)进行检查。

使用random_shuffle

一种简单的方法是对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)的大小可比,则此方法效果很好,因为随机改组的复杂性将在较大的结果集上摊销。

使用“ uniform_int_distribution”

如果要选择的随机数的大小远小于总数的大小,则可以使用另一种方法:

#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;
}