我有一个n个整数数组,只能假设 log n 可能的值(以及任何值)。例如,在S = [349,12,12,283,349,283,283,12]
中,只有3个不同的数字(log 8 = 3)
。
我必须在不到O(nlogn)
的时间内对此数组进行排序。我应该使用哪种算法?也许Radix排序计数排序?它的分析怎么样?
答案 0 :(得分:3)
由于给定的是只有log(n)
个唯一元素,您可以使用以下算法在O(n)
时间内获取排序列表:
O(n)
步骤。log(n)
排序上面的元组列表。
k*log(k)
,其中k
是输入的大小。 k
替换为log(n)
,我们将此步骤的复杂性视为O(log(n)*log(log(n)))
。O(log(n)*log(log(n)))
< O(n)
,因此直到此步骤的总体复杂度为O(n) + O(log(n)*log(log(n)))
,这相当于O(n)
。O(n)
次迭代。总的来说,上面的算法将在O(n)时间运行。
答案 1 :(得分:2)
总的来说,这是O(n)并且易于实现。
这里有一些python实现了这个:
def duplicates_sort(xs):
keys = collections.Counter(xs)
result = []
for k in sorted(keys):
result.extend([k] * keys[k])
return result
答案 2 :(得分:1)
基数排序复杂度为O(dn)
,其中d为数字中的位数。
算法仅在d为常数时才以线性时间运行!在您的情况下,d = 3log(n),您的算法将在O(nlog(n))
中运行。
老实说,我不确定如何在线性时间内解决这个问题。是否有关于数字性质的其他信息,我想知道是否有任何其他信息缺失关于数字的性质......
嗯,这是DNA的MSD基数排序的简单实现。它是用D语言编写的,因为这是我最常使用的语言,因此最不可能犯下愚蠢的错误,但它很容易被翻译成其他语言。它就位,但要求2 * seq.length通过阵列。
void radixSort(string[] seqs, size_t base = 0) {
if(seqs.length == 0)
return;
size_t TPos = seqs.length, APos = 0;
size_t i = 0;
while(i < TPos) {
if(seqs[i][base] == 'A') {
swap(seqs[i], seqs[APos++]);
i++;
}
else if(seqs[i][base] == 'T') {
swap(seqs[i], seqs[--TPos]);
} else i++;
}
i = APos;
size_t CPos = APos;
while(i < TPos) {
if(seqs[i][base] == 'C') {
swap(seqs[i], seqs[CPos++]);
}
i++;
}
if(base < seqs[0].length - 1) {
radixSort(seqs[0..APos], base + 1);
radixSort(seqs[APos..CPos], base + 1);
radixSort(seqs[CPos..TPos], base + 1);
radixSort(seqs[TPos..seqs.length], base + 1);
}
}
显然,这是一种特定的DNA,而不是一般的,但它应该很快。
编辑:我很好奇这段代码是否真的有效,所以我在等待自己的生物信息学代码运行的同时测试/调试了它。现在上面的版本实际上已经过测试和运行。对于每个5个碱基的1000万个序列,它比优化的 introsort 快约3倍。
让我们看两个十进制数的例子:
49, 25, 19, 27, 87, 67, 22, 90, 47, 91
按第一位数排序
19, 25, 27, 22, 49, 47, 67, 87, 90, 91
接下来,按第二个数字排序,产生
90, 91, 22, 25, 27, 47, 67, 87, 19, 49
似乎错了,不是吗?或者这不是你在做什么?如果我弄错了,也许你可以告诉我们代码。
如果您对具有相同第一个数字的所有组进行第二次排序,则您的算法将等同于递归版本。它也会稳定。唯一的区别是你要对广告优先级进行排序,而不是深度优先。
更新
检查此答案:sort O(nlogn)