这是我坚持的功课问题。
我需要对n元素数组进行排序,以便第一个k元素最低并且按升序排列。对于k <= n / log(n),算法应为O(n)。
我的解决方案: 我想到的一个简单的解决方案是堆积(O(n))数组。然后删除k元素并将堆/数组的起始索引从0移到1 - 2 - 3(依此类推,一直到k)。这将是O(n + k * lg(n)+ k * n)= O(kn + k * lg(n))。对于给定的k条件,它将是O(n ^ 2 / log(n)+ n)。
另一个可能的实现是使用基数排序,这将是O(n),但我感觉这不是正确的解决方案,因为我将整个数组排序,他们只要求排序k元素。
你不必给我答案,只是提示会有所帮助。
答案 0 :(得分:-1)
我发现你可以使用略微修改的堆选择算法就地执行此操作,即O(n log k)。虽然渐近“差”比Quickselect的O(n)复杂度更差,但是当k与n相比非常小时,堆选择可以胜过Quickselect。有关详细信息,请参阅When theory meets practice。但是,如果你选择一百万个列表中的前1000个项目,那么堆选择几乎肯定会更快。
无论如何,要在适当的位置执行此操作,您将从数组中的前k个项构建数组前面大小为k的max-heap(使用标准BuildHeap函数)。这需要O(k)。然后,您将处理数组中的其余项目,如下所示:
for (i = k; i < length; ++i)
{
if (array[i] < array[0]) // If item is smaller than largest item on heap
{
// put large item at the current position
temp = array[i];
array[i] = array[0];
// put new item at the top of heap and sift it down
array[0] = temp;
SiftDown(0);
}
}
这将花费O(n log k)时间,但限制因素实际上是您必须在条件内执行代码的次数。仅当项目小于堆上已有的最大项目时,此步骤才会进行任何处理。最糟糕的情况是阵列处于反向排序顺序。否则它会出乎意料地快。
完成后,最小的k项位于数组的前面。
然后你必须对它们进行排序,即O(k log k)。
因此完整的程序是O(k + n log k + k log k)。同样,当k远小于n时,这比Quickselect要快得多。