我需要对任意长度的大量文本字符串进行排序。我认为基数排序是最好的选择。列表真的很大,所以填充字符串到相同的长度是完全不可能的 是否有任何现成的实现,最好是在C#?
答案 0 :(得分:2)
根据您的需要,您可能会发现将所有字符串插入某种形式的Trie是最佳解决方案。即使是基本的三元搜索工具也会比数组/字符串列表具有更小的内存占用,并且将按排序顺序存储字符串。
插入,查找和删除都是O(k * log(a))
,其中a
是字母表的大小(字符的可能值的数量)。由于a
是常量,因此log(a)
因此您最终会使用O(n * k)
算法进行排序。
编辑:如果您不熟悉Tries,它们基本上是n-ary树,其中每条边代表键的单个字符。插入时,检查根节点是否包含与键的第一个字符匹配的边(或子节点)。如果是,则按照该路径重复第二个字符,依此类推。如果没有,则添加新边。在三元搜索Trie中,边/子项存储在二叉树中,因此字符按排序顺序排列,可以在log(a)
时间内搜索。如果你想浪费内存,可以将边/子存储在一个大小为a
的数组中,这样就可以在每一步中不断查找。
答案 1 :(得分:1)
查看此主题。 radix sort 或此radix sort implementation
答案 2 :(得分:0)
有多少,一百万?
内置List<string>.Sort()
平均需要O(n * log(n))。
log2(10 ^ 6)〜= 20,对于10 ^ 6个元素,它不比O(n)慢得多。如果你的字符串长度超过20个字符,则基数排序O(n * k)将“慢”。
我怀疑基数排序会比内置排序快得多。但衡量和比较会很有趣。
答案 3 :(得分:0)
编辑:我之前提到的这些陈述有一点意义,但总的来说这是错误的。
基数排序是在大量字符串上使用的错误排序。对于像
这样的事情I really like squirrels. Yay, yay, yay!
I really like blue jays. Yay, yay, yay!
I really like registers. Yay, yay, yay!
你会有一堆条目落在同一个桶中。您可以通过散列来避免这种情况,但是使用散列代码的用途是什么?
使用quicksort或mergesort等。 (Quicksort通常表现更好,占用内存更少,但很多例子都有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
}
}
时间是7M行源代码(100x重复70k行),基数排序与内置库排序相关联,之后获胜。
答案 4 :(得分:-2)
String.Compare()重载正在使用这种字符串比较。看看你需要的是把它喂给你 排序算法。
<强>更新强>
这是实施:
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern int nativeCompareString(int lcid, string string1, int offset1, int length1, string string2, int offset2, int length2, int flags);
使用您自己的实现很难击败这个本机非托管实现。