对于给定的N个实数数组,每个数字都有自己的键,但键不一定不同。众所周知,我们有k个不同的密钥。
当k = O(log N)时,我需要在O(N log(log N))复杂度中找到一个稳定的排序算法, 我可以使用额外的O(N)空间?
我尝试了一切,我想不出任何事情。
答案 0 :(得分:3)
正如Tilman Vogel指出的那样,有些算法理论上可以通过对输入数据施加特定限制来以Θ(n log(log n))复杂度运行。看起来它们不太可能在大多数实际应用程序中提供很大的好处,也可能是我从未见过实现的原因,但如果它们适合您的用例,我会很好奇地看看这些算法的基准测试是否更快。
这是Steven S. Skiena的算法设计手册的摘录,解释了为什么不可能提出通用Θ(n log(log n))排序算法:
我们已经看到几种排序算法在最坏情况下运行O(n log n)时间,但没有一种是线性的。要对n项进行排序当然需要查看所有项,因此在最坏的情况下,任何排序算法都必须是Ω(n)。我们可以关闭剩余的Θ(log n)间隙吗?
答案是否定的。可以通过观察任何排序算法在每个不同的n上执行期间必须表现出不同的行为来显示Ω(n log n)下限! n个密钥的排列。每个成对比较的结果控制任何基于比较的排序算法的运行时行为。我们可以把这样一个算法的所有可能执行的集合想象成一个带有n的树!树叶。最小高度树对应于最快的算法,它发生在lg(n!)=Θ(n log n)。
答案 1 :(得分:1)
http://en.wikipedia.org/wiki/Sorting_algorithm声称Han和Thorup的算法具有您所需的复杂性。
答案 2 :(得分:1)
要实现此约束,我们必须考虑树,特别是二叉搜索树。存在一类二进制搜索树,在节点中有一些额外的信息,如父,左子,右子和颜色......是的,我说的是红黑树。在RB树中插入一个节点的时间复杂度是O(log n),n是树的节点数。基本思路是遍历数组,并在RB树中插入每个元素,但是如果我们检测到重复元素,则使用一个约束,不要插入!!!,只计算!怎么做?简单,只需在节点中添加一个字段“count”,每次找到重复元素时只需增加计数器,但不要插入新节点。这样做,RB树只有O(k)个元素,即我们的例子中的O(log n)。因此,在RB树中插入一个节点的复杂性是O(log(log n))。一旦我们在RB树中插入所有元素,时间复杂度将为O(n log(log n))。下一步是按顺序遍历树!!并复制计数器所在的每个元素。这样做我们有排序数组(RB树是二叉搜索树),并且因为按顺序遍历的时间复杂度是O(n),所以总体时间复杂度将是O(n log(log n))。
答案 3 :(得分:0)
当他描述的原始算法基本上是对BucketSort或RadixSort的描述时,你们正在考虑“传统的”排序算法(冒泡,合并,快速等)。这些不属于Ω(nlogn)限制,因为它们不执行二进制比较,而是根据要排序的项目数进行比较!
我只能猜测,对于多对数键的Radixsort形式或要排序的n个项的值,可以具有所需的复杂性。但是我并不是100%肯定,因为我没有测试过它也没有证明它。
答案 4 :(得分:0)
我们正在处理比较模型,而不是单词ram模型。众所周知,我们无法遍历下限n log h
,其中n
是输入大小,h
是容器中元素的数量。在排序算法中,我们可以通过任何平衡的二叉搜索树(包括 RBT 和 AVL )和优先级队列(笛卡尔树排序)来达到上限。
在这种情况下,关键是所选容器的大小不能大于h = k = log n
(由于普遍性,我们一般说h = n
)。本质上,raul_zevahc有了这个想法,我们只需要稍微修改一下解决方案即可实现稳定排序。代替计数(实际上是在计算集合中的元素数),我们为每个节点维护一个 queue (先进先出)。每当遍历一个节点时,我们都会弹出该节点的所有元素。
对于不稳定的排序算法,我们总是可以将其更改为稳定的算法,而这需要花费线性时间进行预处理。