C ++ Как сгенерировать 10000 уникальных случайных целых чисел для хранения в BST?

Я ответил на этот вопрос другим вопросом SO, прежде чем принять решение включить мой ответ в качестве ответа на этот поток, потому что никто не обращался к тому, как требовать / не требовать элементов, просто выдавая регулярные выражения: Regex работает неправильно, сопоставление неожиданных вещей

Из моего сообщения на этом сайте я создал краткое руководство, помогающее любому пользователю создать собственное регулярное выражение для собственного формата номера телефона, о котором я буду предупреждать (например, Я сделал это на другом сайте), что, если вы слишком ограничительны, вы не можете получить желаемые результаты, и нет решения «одного размера подходит всем» для принятия всех возможных телефонных номеров в мире - только то, что вы решите принять в качестве ваш формат выбора. Используйте на свой страх и риск.

Быстрый лист обмана

  • Запустите выражение: /^
  • Если вы хотите потребовать пробел, используйте: [\s] или \s
  • Если вы хотите скопировать скобки, используйте: [(] и [)]. Использование \( и \) является уродливым и может сбить с толку.
  • Если вы хотите, чтобы что-то было необязательным, поставьте ? после него
  • Если вы хотите дефис , просто введите - или [-]. Если вы не ставите его первым или последним в ряд других символов, вам может потребоваться его избежать: \-
  • Если вы хотите принять разные варианты в слоте, поместите скобки вокруг options: [-.\s] потребует дефис, период или пробел. Значок вопроса после последней скобки сделает все из них необязательными для этого слота.
  • \d{3}: Требуется 3-значное число: 000-999. Сокращение для [0-9][0-9][0-9].
  • [2-9]: для этого слота требуется цифра 2-9.
  • (\+|1\s)?: принять «плюс» или 1 и пробел (символ трубы, | , является «или») и делает его необязательным. Знак «плюс» должен быть экранирован.
  • Если вы хотите, чтобы определенные числа соответствовали слоту, введите их: [246] потребует 2, 4 или 6. [77|78] потребует 77 или 78 .
  • $/: Завершить выражение

1
задан Christophe 24 March 2019 в 19:59
поделиться

3 ответа

В вашем коде есть пара проблем. Но давайте прямо к больно.

В чем главная проблема?

Из вашего кода очевидно, что 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. Навигация по узлу требует сравнения со значением в текущем узле и, в зависимости от результата, повторяется, продолжая либо с указателем влево или вправо, не используя индексацию. Но это было бы слишком долго, чтобы объяснить здесь. Так что, может быть, вы должны искать учебник, как этот

0
ответ дан Christophe 24 March 2019 в 19:59
поделиться

Для множества уникальных «случайных» чисел я обычно использую Формат сохраняющего шифрование . Поскольку шифрование является взаимно-однозначным, вам гарантированы уникальные выходные данные, если они являются уникальными. Другой ключ шифрования будет генерировать другой набор выходных данных, то есть другую перестановку входных данных. Просто зашифруйте 0, 1, 2, 3, 4, ... и выходные данные гарантированно уникальны.

Вы хотите цифры в диапазоне [1 .. 20 000]. К сожалению, для 20000 требуется 21 бит, и большинство схем шифрования имеют четное количество бит: в вашем случае 22 бита. Это означает, что вам нужно будет ездить на велосипеде; повторно зашифруйте вывод, если число слишком велико, пока не получите число в нужном диапазоне. Поскольку ваши входные данные доходят только до 10 000, а количество циклов выше 20 000, вы все равно избегаете дублирования.

Единственный известный мне стандартный шифр, который допускает 22-битный размер блока, - это шифр Hasty Pudding. В качестве альтернативы достаточно просто написать свой собственный простой шифр Фейстеля . Четыре раунда достаточно, если вы не хотите криптографическую безопасность. Для защиты на криптографическом уровне вам необходимо использовать AES / FFX, который одобрен NIST.

0
ответ дан rossum 24 March 2019 в 19:59
поделиться

Есть два способа, с помощью которых вы можете выбрать случайные уникальные числа из последовательности , не проверяя по ранее выбранным номерам (т. Е. Уже в вашем BST).

Использовать random_shuffle

Простой способ - перетасовать отсортированный массив из 1 ... 20 000 и просто выбрать первые 10000 элементов:

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

Этот метод хорошо работает, если размер случайных чисел (10000) для выбора сравнимо с размером общих чисел (20000), потому что сложность случайного перетасовки амортизируется по большему набору результатов.

Использоватьiform_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;
}
0
ответ дан Edy 24 March 2019 в 19:59
поделиться
Другие вопросы по тегам:

Похожие вопросы: