对n元素数组进行排序,使得第一个k元素按递增顺序排列最低(就地算法)

时间:2014-06-15 03:35:04

标签: arrays algorithm sorting radix-sort counting-sort

这是我坚持的功课问题。

我需要对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元素。

你不必给我答案,只是提示会有所帮助。

1 个答案:

答案 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要快得多。