题
堆是一个列表,其中适用以下内容:
l[i] <= l[2*i] && l[i] <= [2*i+1]
表示0 <= i < len(list)
我正在寻找就地排序。
解决方案
通过将数据放在堆中,您已经完成了堆排序。您只需要实现堆排序算法的第二部分。这应该比在堆数组上使用quicksort更快。
如果你有勇气,可以去实施 smoothsort ,对于近乎整理的数据来说,它比heapsort更快。
其他提示
只需使用堆排序。它是就地的。那将是最自然的选择。
您也可以使用您的堆,并使用其他算法对其进行排序。然后,您从排序列表中重新构建堆。 Quicksort是一个很好的候选者,因为你可以确定它不会在最坏情况下的O(n <!>#178;)顺序运行,因为你的堆已经预先排序了。
如果您的比较功能很昂贵,那可能会更快。堆排序倾向于经常评估比较函数。
对就地堆排序的声音类似于堆排序的工作。
我认为内存受限制,也许是嵌入式应用程序?
由于你已经有了堆,你不能只使用堆sort <的第二阶段吗? / A>?它起作用,应该是好的和有效的。
对于就地排序,最快的方法如下。请注意我的代码中的逐个错误。请注意,此方法提供了反向排序列表,需要在最后一步中取消。如果你使用max-heap,这个问题就会消失。
一般的想法是巧妙的:将最小的元素(在索引0处)与堆中的最后一个元素交换,将该元素向下鼓泡直到堆属性恢复,将堆的大小缩小一并重复。
这不是非就地排序的绝对最快方式,因为David Mackay演示这里 - 你可以通过在堆顶部放置一个最小的元素而不是底行的一个元素来做得更好。
时间复杂度是T(n.log n)最坏情况 - n次迭代可能有log n(堆的高度)经过while循环。
for (int k=len(l)-1;k>0;k--){
swap( l, 0, k );
while (i*2 < k)
{
int left = i*2;
int right = l*2 + 1;
int swapidx = i;
if ( l[left] < l[right] )
{
if (l[i] > l[left])
{
swapidx = left;
}
}
else
{
if (l[i] > l[right])
{
swapidx = right;
}
}
if (swapidx == i)
{
// Found right place in the heap, break.
break;
}
swap( l, i, swapidx );
i = swapidx;
}}
// Now reverse the list in linear time:
int s = 0;
int e = len(l)-1;
while (e > s)
{
swap( l, s, e );
s++; e--:
}
逐个读取堆顶部的项目。基本上你所拥有的是堆排序。
不隶属于 StackOverflow