排序堆的最快方法(至少在理论上)是什么?

时间:2008-09-22 09:35:51

标签: sorting heap

堆是一个列表,其中适用以下内容:

l[i] <= l[2*i] && l[i] <= [2*i+1]

代表0 <= i < len(list)

我正在寻找就地排序。

6 个答案:

答案 0 :(得分:2)

只需使用堆排序。它是就地的。那将是最自然的选择。

您也可以使用您的堆,并使用其他算法对其进行排序。然后,您从排序列表中重新构建堆。 Quicksort是一个很好的候选者,因为你可以确定它不会在最坏情况下的O(n²)顺序运行,因为你的堆已经预先排序了。

如果您的比较功能很昂贵,那可能会更快。堆排序倾向于经常评估比较函数。

答案 1 :(得分:1)

通过将数据放在堆中,您已经完成了堆排序。您只需要实现堆排序算法的第二部分。这应该比在堆数组上使用quicksort更快。

如果你感到勇敢,你可以去实施smoothsort,这比近乎整理的数据更快。

答案 2 :(得分:0)

对就地堆排序的声音类似于Heap Sort的作业。

我认为内存受限制,也许是嵌入式应用程序?

答案 3 :(得分:0)

既然你已经有了堆,那么你不能只使用heap sort的第二阶段吗?它起作用,应该是好的和有效的。

答案 4 :(得分:0)

对于就地排序,最快的方法如下。请注意我的代码中的逐个错误。请注意,此方法提供了反向排序列表,需要在最后一步中取消。如果你使用max-heap,这个问题就会消失。

一般的想法是巧妙的:将最小的元素(在索引0处)与堆中的最后一个元素交换,将该元素向下鼓泡直到堆属性恢复,将堆的大小缩小一并重复。

这不是非就地排序的绝对最快方式,因为David Mackay演示here - 您可以通过将一个元素放在堆顶部而不是最小的元素来做得更好从最下面一行开始。

时间复杂度是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--:
  }

答案 5 :(得分:-1)

逐个读取堆顶部的项目。基本上你所拥有的是堆排序。