При выполнении некоторых задач требуется перемешать случайным образом (перетасовать) массив или список с данными. Для решения данной проблемы существуют специальные алгоритмы. Рассмотрим один один из таких алгоритмов под названием Тасование Фишера-Йетса.
Алгоритм Фишера — Йетса (Современная версия)
Тасование Фишера-Йетса (Fisher–Yates shuffle) используется для выполнения случайных перестановок множества элементов. Например, массивов или списков.
На псевдокоде алгоритм можно представить следующим образом:
1 2 3 4 |
Чтобы перемешать массив a из n элементов (индексы элементов от 0 до n - 1): для всех i от n − 1 до 1 выполнить j ← случайное число 0 ≤ j ≤ i обменять местами a[j] и a[i] |
Ниже будут приведены реализации данного алгоритма на языках Си и C#.
Перемешать массив на Си
Перемешать элементы массива, состоящего из целых чисел, на языке программирования Си можно с помощью следующей функции shuffle (реализованной ниже). Пример программы:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
#include <stdio.h> #include <cstdlib> #include <ctime> // arr - массив для перестановки, N - количество элементов в массиве void shuffle(int* arr, int N) { // инициализация генератора случайных чисел srand(time(NULL)); // реализация алгоритма перестановки for (int i = N - 1; i >= 1; i--) { int j = rand() % (i + 1); int tmp = arr[j]; arr[j] = arr[i]; arr[i] = tmp; } } int main() { int arr[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; shuffle(arr, 10); for (int i = 0; i < 10; i++) printf("%d ", arr[i]); printf("\n"); return 0; } |
Результат работы программы (изначально массив был заполнен десятичными цифрами в порядке от 0 до 9):
Можно отредактировать функцию shuffle, изменив тип данных массива, указав вместо целого типа данных int, любой другой нужный.
Перемешать массив на C#
Перемешать элементы массива целых чисел на языке C# можно с помощью следующего метода, реализующего алгоритм Фишера — Йетса:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
public static void Shuffle(int[] arr) { // создаем экземпляр класса Random для генерирования случайных чисел Random rand = new Random(); for (int i = arr.Length - 1; i >= 1; i--) { int j = rand.Next(i + 1); int tmp = arr[j]; arr[j] = arr[i]; arr[i] = tmp; } } |
Целый тип int можно заменить на любой другой, который вам потребуется.
Чтобы не дублировать код, создавая методы под каждый тип данных, можно создать один универсальный метод, используя обобщения C#:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public static void Shuffle<T>(T[] arr) { Random rand = new Random(); for (int i = arr.Length - 1; i >= 1; i--) { int j = rand.Next(i + 1); T tmp = arr[j]; arr[j] = arr[i]; arr[i] = tmp; } } |
Как перемешать список на C#
Тасование Фишера-Йетса также можно использовать для перемешивания списков и других коллекций. Реализуем алгоритм для случайной перестановки элементов списка List на C#, используя обобщенный тип данных.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public static void Shuffle<T>(List<T> list) { Random rand = new Random(); for (int i = list.Count - 1; i >= 1; i--) { int j = rand.Next(i + 1); T tmp = list[j]; list[j] = list[i]; list[i] = tmp; } } |
Для более удобного использования метода перемешивания элементов, можно создать потомка класса коллекции (например списка) и реализовать в классе-потомке данный метод.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
class MyList<T> : List<T> { public void Shuffle() { Random rand = new Random(); for (int i = this.Count - 1; i >= 1; i--) { int j = rand.Next(i + 1); T tmp = this[j]; this[j] = this[i]; this[i] = tmp; } } } |
Дальнейшее создание списка и применение метода перемешивания элементов, будет реализовываться следующим образом:
1 2 3 4 5 6 |
MyList<int> myList = new MyList<int>(); for (int i = 0; i < 10; i++) myList.Add(i); myList.Shuffle(); |
Стоит отметить, что в языке Java у коллекций (например у ArrayList) уже есть реализованный метод с названием shuffle, перемешивающий элементы.
Поделиться в соц. сетях: