Редактировать: в этих утверждениях, которые я делал ранее, есть точка, но в целом эта точка неверна.
Сортировка по радикалам - это неправильная сортировка для большого числа строк.Для таких вещей, как
I really like squirrels. Yay, yay, yay!
I really like blue jays. Yay, yay, yay!
I really like registers. Yay, yay, yay!
, у вас будет куча записей, попадающих в одну корзину.Вы можете избежать этого путем хеширования, но какая польза от сортировки хеш-кода?
Используйте быструю сортировку, слияние или тому подобное.(Быстрая сортировка обычно работает лучше и занимает меньше памяти, но во многих примерах производительность O (N ^ 2) в худшем случае почти не встречается на практике; Mergesort работает не так хорошо, но обычно реализуется для обеспечения стабильности, и этолегко сделать часть в памяти и часть на диске.) То есть, использовать встроенную функцию сортировки.
Редактировать: Ну, получается, что по крайней мере на очень больших файлах с длинными повторениями вВ начале (например, исходный код) и со многими одинаковыми строками (фактически 100-кратными повторениями) сортировка по основанию начинает конкурировать с быстрой сортировкой.Я удивлен!Но, в любом случае, вот код, который я использовал для реализации радикальной сортировки.Он написан на Scala, а не на C #, но я написал его в довольно итеративном стиле, поэтому должно быть достаточно очевидно, как все работает.Единственные два хитрых бита в том, что (a(i)(ch) & 0xFF)
предназначен для извлечения 0-255 байт из массива массивов байтов (байты подписаны), что counts.scanLeft(0)(_ + _)
формирует накопленную сумму отсчетов, начиная с нуля (а затем indices.clone.take(257)
принимает все, кроме последнего), и что Scala допускает несколько списков параметров (поэтому я отделил всегда предоставленный аргумент от аргументов, которые имеют значения по умолчанию, которые используются в рекурсии).Вот оно:
def radixSort(a: Array[Array[Byte]])(i0: Int = 0, i1: Int = a.length, ch: Int = 0) {
val counts = new Array[Int](257)
var i = i0
while (i < i1) {
if (a(i).length <= ch) counts(0) += 1
else { counts((a(i)(ch)&0xFF)+1) += 1 }
i += 1
}
val indices = counts.scanLeft(0)(_ + _)
val starts = indices.clone.take(257)
i = i0
while (i < i1) {
val bucket = if (a(i).length <= ch) 0 else (a(i)(ch)&0xFF)+1
if (starts(bucket)+i0 <= i && i < starts(bucket)+i0+counts(bucket)) {
if (indices(bucket) <= i) indices(bucket) = i+1
i += 1
}
else {
val temp = a(indices(bucket)+i0)
a(indices(bucket)+i0) = a(i)
a(i) = temp
indices(bucket) += 1
}
}
i = 1
while (i < counts.length) {
if (counts(i)>1) {
radixSort(a)(i0+starts(i),i0+starts(i)+counts(i),ch+1)
}
i += 1
}
}
И время таково, что при 7М строках исходного кода (100-кратное дублирование по 70 тыс. Строк) радикальная сортировка связывает встроенную библиотечную сортировку и выигрывает после этого.