Алгоритм для генерации N чисел с rand () без дубликатов [duplicate]

Я использую SQL Server 2016 и Window 10.

Прежде всего, нужно разрешить удаленное подключение к SQL Сервер. Я сделал, чтобы ввести sqlservermanager13.msc в меню «Пуск», чтобы открыть диспетчер конфигурации SQL Server. Убедитесь, что статус TCP / IP включен.

Проверьте номер своего TCP-порта, дважды щелкнув имя протокола TCP / IP. Обычно это по умолчанию 1433.

Следующие процедуры настраивают брандмауэр Windows с помощью оснастки «Брандмауэр Windows с расширенной безопасностью» Microsoft Management Console (MMC) -в. Брандмауэр Windows с расширенной безопасностью настраивает только текущий профиль.

Чтобы открыть порт в брандмауэре Windows для доступа к TCP

  1. В меню «Пуск» выберите «Выполнить», введите WF.msc и нажмите «ОК».
  2. В брандмауэре Windows с расширенной безопасностью на левой панели щелкните правой кнопкой мыши Правила входящих сообщений и выберите «Новое правило» на панели действий.
  3. В диалоговом окне «Тип правила» выберите Порт, а затем нажмите «Далее».
  4. В диалоговом окне «Протокол и порты» выберите TCP. Выберите «Определенные локальные порты», а затем введите номер порта экземпляра Database Engine, например 1433 для экземпляра по умолчанию. Нажмите «Далее».
  5. В диалоговом окне «Действие» выберите «Разрешить подключение» и нажмите «Далее».
  6. В диалоговом окне «Профиль» выберите любые профили, описывающие среду подключения к компьютеру, когда вы хотите подключиться к механизму базы данных, а затем нажмите «Далее».
  7. В диалоговом окне «Имя» введите имя и описание этого правила и нажмите «Готово».

Еще одна вещь, которую нужно настроить.

Чтобы открыть доступ к SQL Server при использовании динамических портов

  1. В меню «Пуск» выберите «Выполнить», введите «WF» .msc, а затем нажмите «ОК».
  2. В брандмауэре Windows с расширенной безопасностью на левой панели щелкните правой кнопкой мыши «Правила входящих» и выберите «Новое правило» на панели действий.
  3. В диалоговом окне «Тип правила» выберите «Программа» и нажмите «Далее».
  4. В диалоговом окне «Программа» выберите «Путь к этой программе». Нажмите «Обзор» и перейдите к экземпляру SQL Server, к которому вы хотите получить доступ через брандмауэр, и нажмите «Открыть». По умолчанию SQL Server находится в папке C: \ Program Files \ Microsoft SQL Server \ MSSQL13.MSSQLSERVER \ MSSQL \ Binn \ Sqlservr.exe. Нажмите «Далее».
  5. В диалоговом окне «Действие» выберите «Разрешить подключение» и нажмите «Далее».
  6. В диалоговом окне «Профиль» выберите все профили, описывающие среду подключения к компьютеру, когда вы хотите подключиться к движку базы данных и нажмите «Далее».
  7. В диалоговом окне «Имя» введите имя и описание этого правила и нажмите «Готово».

Взгляните на Microsoft doucmentation Настройте брандмауэр Windows для доступа к базе данных

33
задан Jonathan Leffler 20 January 2017 в 23:12
поделиться

6 ответов

В стандарте C нет функции для рандомизации массива.

  • Посмотрите на Кнута - у него есть алгоритмы для задания.
  • Или посмотрите на Bentley

Обеспечение правильной перетасовки (где каждая перестановка исходного порядка одинаково вероятна).

  • Или посмотреть практически в любую книгу алгоритмов.
  • просто, но не тривиально.

    33
    ответ дан Jonathan Leffler 18 August 2018 в 23:34
    поделиться
    • 1
      Чтобы избежать распределения t с каждой итерацией, вы должны поменять местами два целых числа без переменной temp: array [i] ^ = array [j]; array [j] ^ = array [i]; array [i] ^ = array [j]; – Hyperboreus 25 May 2011 в 17:37
    • 2
      вы также можете сделать array[i] += array[j]; array[j] = array[i] - array[j]; array[i] -= array[j];, если вы не беспокоитесь о переполнении int. Я не хочу путать с новичком язык о том, почему XOR'ing работает, хотя ... – John Leehey 25 May 2011 в 17:44
    • 3
      @Hyperboreus - Вы шутите? & Quot; & Quot Выделение; целые числа в стеке так же просто, как выполнение сложения / вычитания в регистре. Это само по себе будет достаточно быстрым, но, кроме того, приличный оптимизатор будет делать это сложение / вычитание только для этого кода, а не для каждой итерации. (Скомпилируйте это с включенной оптимизацией и посмотрите на разборку для себя. Я сделал это с помощью gcc -S, и были только два модификации указателя стека, один раз в начале функции и один раз в конец.) Вы сохраняете nothing , используя ранее t и j в этой функции. – asveikau 25 May 2011 в 17:53
    • 4
      Действительно одинаково вероятно очень сложно. Например, ваш генератор случайных чисел должен иметь кратное N! состояния. – user 25 May 2011 в 20:14
    • 5
      @Paul: Пока ваше PRNG «случайное число между 1 и N» обертка правильная (равномерное распределение), это легко. Однако люди часто прикручивают это и создают предвзятость. – R.. 25 May 2011 в 21:35
    • 6
      @Paul Hankin: Это потому, что вам нужно генерировать случайные числа от 0 до i, где i идет от n до 1? – ninjalj 25 May 2011 в 21:38
    • 7
      @ninjalj: Нет, абсолютно нет. Это наивный сломанный алгоритм, который каждый использует. Все, что с плавающей запятой в нем будет черным, будет правильным, поэтому первым шагом к его исправлению будет переход на целые числа. Затем отбросьте любые результаты, превышающие наибольшее кратное 10, минус 1 (снова вызовите rand, если вы получите значение, которое вы должны отбросить). Есть способы сохранить и повторно использовать эту энтропию, а не полностью отбросить ее, но это больше работает и, вероятно, бесполезно, когда она просто псевдослучайна в любом случае. – R.. 25 May 2011 в 21:51
    • 8
      @Р. glibc rand () имеет только 2 ^ 32 разных состояния, поэтому он может генерировать не более 2 ^ 32 разных перетасовки пачки карт, что бы вы ни делали. 52! больше похож на 2 ^ 225, поэтому вы фактически генерируете крошечную, крошечную часть всех возможностей. – user 27 May 2011 в 20:18
    • 9
      Примечание. Формула i + r / (RAND_MAX / (n - i) + 1) вводит дополнительное смещение. например j (i = 32, n = 61, RM = 2147483647) - & gt; {с 2147483648 различными r, j = 32 - 60 встречается 74051161 каждый, 61 - только 74051140}. TBD наихудший случай i,n,RAND_MAX. С i+ rnd%(n-i) {j = от 32 до 39 встречаются 74051161 каждый, j = от 40 до 61 происходит 74051160, распределение худшего случая для различных i,n,RAND_MAX не более 1 раз. Поскольку другие сообщения ссылаются на этот популярный ответ, это было важно заметить. – chux 26 April 2014 в 17:36
    • 10
      @PaulStelian: Если RAND_MAX всего 32767, вам нужно получить лучшее PRNG. Одним простым шагом является семейство функций drand48(); это стандартный набор функций POSIX. Вы можете обнаружить, что у вас есть random() и srandom() или arc4random(), или, возможно, вы можете использовать /dev/random или /dev/urandom в качестве источника случайных значений. Есть много возможностей, но то, что вы задаете, - это действительно новый вопрос (или его следует задать по новому вопросу). – Jonathan Leffler 9 June 2018 в 18:15
    33
    ответ дан Jonathan Leffler 30 October 2018 в 11:16
    поделиться

    Я не видел этого среди ответов, поэтому предлагаю это решение, если оно может помочь кому угодно:

    static inline void shuffle(size_t n, int arr[])
    {
        size_t      rng;
        size_t      i;
        int         tmp[n];
        int         tmp2[n];
    
       memcpy(tmp, arr, sizeof(int) * n);
        bzero(tmp2, sizeof(int) * n);
        srand(time(NULL));
        i = 0;
        while (i < n)
        {
            rng = rand() % (n - i);
            while (tmp2[rng] == 1)
                ++rng;
            tmp2[rng] = 1;
            arr[i] = tmp[rng];
            ++i;
        }
    }
    
    1
    ответ дан 421 18 August 2018 в 23:34
    поделиться

    Здесь решение, которое использует memcpy вместо назначения, поэтому вы можете использовать его для массива по произвольным данным. Вам потребуется в два раза больше памяти исходного массива, а стоимость - линейная O (n):

    void main ()
    {
        int elesize = sizeof (int);
        int i;
        int r;
        int src [20];
        int tgt [20];
    
        for (i = 0; i < 20; src [i] = i++);
    
        srand ( (unsigned int) time (0) );
    
        for (i = 20; i > 0; i --)
        {
            r = rand () % i;
            memcpy (&tgt [20 - i], &src [r], elesize);
            memcpy (&src [r], &src [i - 1], elesize);
        }
        for (i = 0; i < 20; printf ("%d ", tgt [i++] ) );
    }
    
    4
    ответ дан Hyperboreus 18 August 2018 в 23:34
    поделиться
    • 1
      Вы также можете сделать это на месте с помощью указателей void *, чтобы снизить потребность в дополнительной памяти и ограничить копирование на отдельные значения - если это массив структур в стеке, это уменьшит количество создаваемых копий. Для еще более низких требований к пространству, смещение смещений в исходной позиции памяти, позволяющее использовать int или меньше (беззнаковое короткое устройство все еще управляет до 65.5k). – Phil H 31 October 2012 в 10:40

    Я просто отвечу на ответ Нила Баттерворта и укажу на некоторые проблемы с вашей первой мыслью:

    Вы предложили

    Итерацию через массив, скажем, 100 раз и обмениваться случайным индексом с другим случайным индексом

    Сделайте это строгим. Я предполагаю существование randn(int n), обертки вокруг некоторого RNG, создавая числа, равномерно распределенные в [0, n -1] и swap(int a[], size_t i, size_t j),

    swap(int a[], size_t i, size_t j) {
      int temp = a[i]; a[i] = a[j]; a[j] = temp;
    }
    

    , который меняет местами a[i] и a[j]. Теперь давайте реализуем ваше предложение:

    void silly_shuffle(size_t n, int a[n]) {
        for (size_t i = 0; i < n; i++)
            swap(a, randn(n), randn(n)); // swap two random elements
    }
    

    Обратите внимание, что это не лучше этой более простой (но все же неправильной) версии:

    void bad_shuffle(size_t n, int a[n]) {
        for (size_t i = 0; i < n; i++)
            swap(a, i, randn(n));
    }
    

    Что ж, что случилось? Рассмотрим, сколько перестановок эти функции дают вам: с помощью n (или 2 × n для silly_shuffle) случайных выборок в [0, n - 1], код будет «справедливо» выбирать один из вариантов n ² (или 2 × n ²]), чтобы перетасовать колоду. Проблема в том, что есть n ! = n × ( n -1) × ⋯ × 2 × 1 возможных компоновки массива, и ни n ², ни 2 × n ² является кратным n !, доказывая, что некоторые перестановки более вероятны, чем другие.

    Shuffle Fisher-Yates на самом деле эквивалентен вашему второму предложению , только с некоторыми изменениями, которые меняются (производительность = 0, сложность = серьезная) до (производительность = очень хорошая, сложность = довольно простая). (На самом деле, я не уверен, что существует более быстрая или более простая версия.)

    void fisher_yates_shuffle(size_t n, int a[n]) {
        for (size_t i = 0; i < n; i++)
            swap(a, i, i+randn(n-1-i)); // swap element with random later element
    }
    

    ETA: См. Также этот пост в Coding Horror .

    2
    ответ дан J. C. Salomon 18 August 2018 в 23:34
    поделиться

    Следующий код гарантирует, что массив будет перетасован на основе случайного семени, взятого из времени usec. Также это реализует Fisher-Yates shuffle должным образом. Я тестировал вывод этой функции, и он выглядит хорошо (даже ожидание того, что любой элемент массива является первым элементом после тасования. Также даже ожидание для последнего).

    void shuffle(int *array, size_t n) {    
        struct timeval tv;
        gettimeofday(&tv, NULL);
        int usec = tv.tv_usec;
        srand48(usec);
    
    
        if (n > 1) {
            size_t i;
            for (i = n - 1; i > 0; i--) {
                size_t j = (unsigned int) (drand48()*(i+1));
                int t = array[j];
                array[j] = array[i];
                array[i] = t;
            }
        }
    }
    
    10
    ответ дан thejartender 18 August 2018 в 23:34
    поделиться
    • 1
      Я бы использовал int, а не size_t, в этом случае, потому что n представляет количество int, а не размер блока памяти. Я предпочитаю использовать size_t только для размеров в байтах. – mk12 6 November 2012 в 20:13
    • 2
      @ Mk12 Число элементов и sizeof массив может быть намного больше, чем INT_MAX. Использование size_t здесь более надежный и переносимый подход. – chux 26 April 2014 в 17:48
    • 3
      Приятно, так мало кода. Быстро и просто ли это работать с библиотекой Microsoft C? – T. Webster 13 May 2015 в 01:00
    • 4
    Другие вопросы по тегам:

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