我想知道是否有一种比quicksort / mergesort更快的方式来排序这样的数组。
最大数组长度为10 ^ 6。 单词的长度为> = 10且< = 100,单词可以包含a-z和空格(总共27个不同的字符)。 字符中的字符不是唯一的(它们可以重复)。 数组中的所有单词都相同。
答案 0 :(得分:7)
您可以将所有字词放在trie(或radix tree)中,然后以DFS顺序打印,从每个级别的“较小”词典字母开始在DFS。
此解决方案为O(n* |S|)
,其中|S|
是字符串的平均长度。
简单示例:
让字符串集为[ac,ab,aca]
:
由此产生的特里将是:
a
/ \
/ \
b c
| / \
$ $ a
|
$
和DFS(更喜欢字典缩写字符):DFS将从a
开始,转到b
,然后到结束标志($
)并将首先打印ab
,然后返回a
,然后转到c
,然后转到下一个$
,并打印ac
,然后在{{旁边1}}及其a
并将打印$
,从而导致打印:
aca
被驱逐。
答案 1 :(得分:1)
任何基于比较的排序的下限是O(nlog(n))。您不能使用任何基于比较元素的排序算法,这些算法在低于此限制的最坏情况下运行。
合并排序和堆排序的最坏情况是运行时间为O(nlog(n))... 快速排序的最坏情况是运行时间为O(n ^ 2),但平均运行时间为O(n ^ log(n))。
值得一提的是,尽管快速排序的运行时间最短,为O(N ^ 2),但由于运行时间较短(如heaps(n)(n)(n)运行时间),因此它有时会因其他算法而失败。在当前机器架构上有效执行的常数因素和适用性。
线性排序算法,允许在非比较基础上以线性时间O(n)对整数(但不仅限于它们)进行排序(例如:计数排序,桶排序和基数排序)
MSD基数排序可以使用字典的数字顺序(在本例中为字符)和从左到右对字符串进行排序。
它首先使用最左边的字符使用另一个线性排序算法(比如桶排序)对所有字符串进行排序,然后使用左边的字符再次对它们进行排序,依此类推,直到它们按最右边的字符排序。 最后,数组将完全排序。
该算法将具有O(k * N)的运行时间,其中N是元素的数量,并且k是平均密钥长度(在这种情况下,字长度将> = 10&&< ; = 100)
答案 2 :(得分:1)
好吧,我已经阅读了(并且已经投票)关于基数排序和基数特里的答案,非常有用。
但是,
在基数排序的情况下 - 您需要进行91次N个元素的传递,因此它将 91 * N 。我不是在谈论额外的空间
在mergesort的情况下,你有 N * log N 比较,并且由于log N = log 1000000~20,你得到 20 * N 比较。
哪一个更快? :) 或者我可能在某个地方弄错了?
答案 3 :(得分:0)
可以计算ascii值,因此基本上这是一个整数排序。基于比较的排序例程最多可以获得O(n lg n) - 合并排序(创建另外两个大小为n / 2的数组所需的额外空间)或最坏的O(n ^ 2)(插入排序,快速排序,但是他们没有额外的空间复杂性)。这些渐近地比线性排序算法慢。我建议查看CLRS(http://www.amazon.com/Introduction-Algorithms-Thomas-H-Cormen/dp/0262033844)。关于线性时间排序的章节。在这种情况下,O(n)可能是你能做的最好的。此外,这篇文章可能有所帮助。 Sorting in linear time?
答案 4 :(得分:0)
为什么不是每三个字符的分布排序:需要19683(27 * 27 * 27)个元素的计数存储,这应该是可行的,然后最多需要34次传递。
但很快,每个键的子列表(三个字符的倍数)将足够短,以便对字符串的剩余部分使用插入排序或类似。 1.000.000 /(27 ^ 3)约为50
如果它们具有共同的长前缀,则相同的机制可以用于较长的密钥,即前30个字符将仅在20或30个子列表中划分列表。那么你不是把数字表示为数字,而是将它们表示为字符串,并将它们存储在一个字典中,这个速度较慢,但是需要较少的传递,也可能是较少的内存。此外,还需要N * log(M)查找,其中M是binairy树中不同键的数量,但散列也是可能的。