- PVSM.RU - https://www.pvsm.ru -
Недавно я увидел быструю сортировку на Haskell [1]. Всего 2 строчки. И решил попробовать написать аналогичную сортировку на C#. Получилось еще лучше — всего одна строчка, хоть и длинная и совсем не такая изящная. Подробности под катом.
Вот сама сортировка:
private static Func<int[], int[]> QSortArray =
arr => arr.Length.Equals(0)
? new int[] {}
: (QSortArray(Array.FindAll(arr, num => num.CompareTo(arr[0]) < 0))
.Concat(Array.FindAll(arr, num => num.CompareTo(arr[0]) == 0))
.Concat(QSortArray(Array.FindAll(arr, num => num.CompareTo(arr[0]) > 0)))).ToArray();
Выглядит сложновато, да, но при знании используемых тут методов разобраться вполне можно. Как работает Func<> проще всего посмотреть в MSDN [2], а остальное я поясню:
Тернарный оператор сравнивает длину массива с нулем. Если длина массива нулевая, то возвращает пустой массив. Если длина ненулевая, начинается самое интересное: сначала находятся все элементы из массива, меньшие первого, с помощью Array.FindAll и сортируются. Аналогично со всеми элементами, равными первому (этих, сортировать, разумеется, не нужно), большими первого. Затем все это «склеивается» с помощью Concat, который возвращает тип IEnumerable, поэтому в конце мы приводим все к массиву методом ToArray(). Подробнее об используемых методах можно посмотреть опять же, в MSDN [3].
private static Func<List<int>, List<int>> QSortList =
arr => arr.Count.Equals(0)
? new List<int>()
: (QSortList(arr.FindAll(num => num.CompareTo(arr[0]) < 0))
.Concat(arr.FindAll(num => num.CompareTo(arr[0]) == 0))
.Concat(QSortList(arr.FindAll(num => num.CompareTo(arr[0]) > 0)))).ToList();
private static Func<IEnumerable<int>, IEnumerable<int>> QSortEnumerable =
arr => arr.Count().Equals(0)
? new List<int>()
: (QSortEnumerable(arr.Where(num => num.CompareTo(arr.First()) < 0)).
Concat(arr.Where(num => num.CompareTo(arr.First()) == 0)).
Concat(QSortEnumerable(arr.Where(num => num.CompareTo(arr.First()) > 0))));
Сортировка, разумеется, значительно медленнее библиотечной — раз в 20 (тестировал на массиве из 5 миллионов чисел: моя сортировка 10 секунд, библиотечная — 0.5 секунды), так что практическую ценность вряд ли имеет. Другого ожидать от алгоритма в одну строку и не стоило, хотя она все равно намного быстрее практически любой квадратичной.
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/pesochnitsa/85166
Ссылки в тексте:
[1] быструю сортировку на Haskell: https://ru.wikibooks.org/wiki/%D0%AF%D0%B7%D1%8B%D0%BA_Haskell:_%D0%9E_%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%B5_%D0%B8_%D0%B2%D1%80%D0%B5%D0%B4%D0%B5_%D0%BB%D0%B5%D0%BD%D0%B8#.D0.91.D1.8B.D1.81.D1.82.D1.80.D0.B0.D1.8F_.D1.81.D0.BE.D1.80.D1.82.D0.B8.D1.80.D0.BE.D0.B2.D0.BA.D0.B0
[2] MSDN: https://msdn.microsoft.com/ru-ru/library/bb549151(v=vs.110).aspx
[3] MSDN: https://msdn.microsoft.com/ru-ru/library/system.array(v=vs.110).aspx
Нажмите здесь для печати.