Очень часто в программах возникает необходимость использования случайных чисел - от заполнения массива до криптографии. Для получения последовательности случайных чисел в языке C# имеется класс Random. Этот класс предусматривает два конструктора:
Random() - инициализирует экземпляр класса Random с помощью начального значения, зависящего от текущего времени. Как известно, время может быть представлено в тиках - 100-наносекундных импульсах, начиная с 1 января 0001 года. И значение времени в тиках представляет собой 64-битное целое число, которое и будет использоваться для инициализации экземпляра генератора случайных чисел.
Random(Int32) - инициализирует экземпляр класса Random с помощью указанного начального значения. Такая инициализация генератора случайных чисел может быть удобна на этапе отладки программы, поскольку в этом случае при каждом запуске программы будут генерироваться одни и те же "случайные" числа.
Основным методом данного класса является метод Next(), позволяющий получить случайное число и имеющий ряд перегрузок:
Next() - возвращает случайное целое неотрицательное число формата Int32.
Next(Int32) - возвращает случайное целое неотрицательное число, которое меньше указанного значения.
Next(Int32 min, Int32 max) - возвращает случайное целое число в указанном диапазоне. При этом должно соблюдаться условие min<max (первый аргумент должен быть меньше второго).
А также методы
NextBytes(Byte[]) - заполняет элементы указанного массива байтов случайными числами.
NextDouble() - возвращает случайное число с плавающей запятой, в диапазоне [0,0; 1,0).
Пример программы, выводящей 100 случайных чисел в диапазоне от -100 до 100.
1 2 3 4 5 6 7 8 9 10 11 12 13 14
using System; namespace MyProgram
{ classProgram
{ staticvoid Main(string[] args)
{ Random rnd = newRandom(); for (int i = 0; i < 100; i++) Console.WriteLine("{0,4}", rnd.Next(-100, 101)); Console.ReadKey();
}
}
}
Однако если создавать новый экземпляр класса Random каждый раз, когда требуется сгенерировать случайное число, то это может привести к тому, что генерируемые числа будут одинаковыми.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
using System; namespace MyProgram
{ classProgram
{ staticvoid Main(string[] args)
{ for (int i = 0; i < 10; i++)
{ Random rnd = newRandom(); Console.WriteLine("{0,4}", rnd.Next(-100, 101));
} Console.ReadKey();
}
}
}
Поэтому для генерации случайных чисел в программе необходимо создать единственный экземпляр класса Random.
Подробнее об этой проблеме смотрите в видео.
Генерация неповторяющейся последовательности чисел
Для генерации последовательности неповторяющихся чисел требуется массив, в котором будут сохраняться уже сгенерированные числа. При этом каждое вновь сгенерированное число сравнивается со всеми уже сгенерированными элементами массива и, в случае несовпадения, добавляется в массив. В случае совпадения числа с одним из элементов массива генерируется новое значение для указанного элемента массива и сравнение повторяется.
using System; namespace MyProgram
{ classProgram
{ staticvoid Main(string[] args)
{ Random rnd = newRandom(); int[] a = newint[100];
a[0] = rnd.Next(0, 101); for (int i = 1; i < 100;)
{ int num = rnd.Next(0, 101); // генерируем элемент int j; // поиск совпадения среди заполненных элементов for (j = 0; j < i; j++)
{ if (num == a[j]) break; // совпадение найдено, элемент не подходит
} if (j == i)
{ // совпадение не найдено
a[i] = num; // сохраняем элемент
i++; // переходим к следующему элементу
}
} for (int i = 0; i < 100; i++)
{ Console.Write("{0,4} ", a[i]); if (i % 10 == 9) Console.WriteLine();
} Console.ReadKey();
}
}
}
Однако чем ближе к концу массива, тем больше генераций необходимо производить для получения неповторяющегося значения.
Следующий пример отображает количество вызовов метода Next() для получения каждого элемента, а также общее количество сгенерированных случайных чисел для заполнения массива из 100 элементов неповторяющимися значениями.
using System; namespace MyProgram
{ classProgram
{ staticvoid Main(string[] args)
{ Random rnd = newRandom(); int[] a = newint[100]; // массив элементов int[] count = newint[100]; // массив количества генераций
a[0] = rnd.Next(0, 101); int c = 0; // счетчик количества генераций
count[0] = 1; // a[0] генерируется только 1 раз for (int i = 1; i < 100;)
{ int num = rnd.Next(0, 101);
c++; // сгенерировали элемент еще один раз int j; for (j = 0; j < i; j++)
{ if (num == a[j]) break;
} if (j == i)
{
a[i] = num; i++;
count[i] = c; c = 0; // сохраняем количество генераций
}
} // Вывод значений элементов Console.WriteLine("Значения элементов"); for (int i = 0; i < 100; i++)
{ Console.Write("{0,4} ", a[i]); if (i % 10 == 9) Console.WriteLine();
} Console.WriteLine(); // Вывод количества генераций Console.WriteLine("Количество генераций элементов"); int sum = 0; for (int i = 0; i < 100; i++)
{
sum += count[i]; Console.Write("{0,4} ", count[i]); if (i % 10 == 9) Console.WriteLine();
} Console.WriteLine("Общее количество генераций - {0}", sum); Console.ReadKey();
}
}
}
Перемешивание значений
Часто возникает задача расставить уже имеющийся набор значений в произвольном порядке. С этой целью также используется генератор случайных чисел. Для решения этой задачи создается массив и заполняется значениями, которые необходимо расставить в произвольном порядке.
После этого генерируется два значения индексов массива случайным образом, и значения элементов с полученными индексами меняются местами. Процедура повторяется не менее N/2 раз, где N - количество элементов массива.
using System; namespace MyProgram
{ classProgram
{ staticvoid Main(string[] args)
{ Random rnd = newRandom(); int[] a = newint[100]; for (int i = 0; i < 100; i++)
a[i] = i; for (int i = 0; i < 50; i++)
{ int i1 = rnd.Next(0, 100); // первый индекс int i2 = rnd.Next(0, 100); // второй индекс // обмен значений элементов с индексами i1 и i2 int temp = a[i1];
a[i1] = a[i2];
a[i2] = temp;
} Console.WriteLine("Значения элементов"); for (int i = 0; i < 100; i++)
{ Console.Write("{0,4} ", a[i]); if (i % 10 == 9) Console.WriteLine();
} Console.ReadKey();
}
}
}
Перемешивание значений является более эффективным если диапазон значений совпадает с их количеством (или близок к нему), поскольку в этом случае значительно сокращается количество генераций случайных элементов.
Автор: Вставская Елена Владимировна
Написать комментарий:
Начинаем практику по языку C#
Чтобы стать хорошим программистом — нужно писать программы.
На нашем сайте очень много практических упражнений.
После заполнения формы ты будешь подписан на рассылку
«C# Вебинары и Видеоуроки»,
у тебя появится доступ к видеоурокам и консольным задачам.
Несколько раз в неделю тебе будут приходить письма —
приглашения на вебинары, информация об акциях и скидках,
полезная информация по C#.