所以我一直在努力实现这个算法,但我不确定从哪里开始。基本上从我的理解,你可以通过两种方式实现它,通过排序顶级是最小值(minHeap)或顶级是最大值(maxHeap)。我搜索了很多关于这两种方式中的任何一种,我无法掌握如何实际实现它。我不会理解这个想法我会说,有人可以解释一下这是如何工作的吗?就像minHeap应该如何工作,或者maxHeap一样。 提前谢谢!
答案 0 :(得分:1)
我假设您对数组中的二进制堆实现有基本的了解。
假设您有一个整数数组,您希望按升序排序。一种方法是重新排列数组中的项目,以便它们形成最大堆。
然后,将顶部项(数组中的最大项)与堆中的最后一项交换,将堆计数减少1,并将项从上到下筛选到堆中的新位置。最后,数组中的第一项将是下一个最大项。您为每个项重复该操作,并对您的数组进行排序。
我们举一个小例子。给定数组[4,7,6,1,3,5,2]
,您可以使用Floyd的算法将它们重新排列到堆中。
for (int i = array.length/2; i >= 0; i--)
{
siftDown(i);
}
这是O(n)操作。
完成后,数组将安排在二进制堆中。在这种情况下,堆将是[7,4,6,1,3,5,2]
或:
7
4 6
1 3 5 2
所以,我们将根项与最后一项交换,给我们:[2,4,6,1,3,5,7]
。我们减少计数并将其筛选到适当的位置,给出:[6,4,5,1,3,2,7]
或堆表示:
6
4 5
1 3 2
(我省略了7,因为我们减少了计数。但它仍然在数组的末尾。)
再次,将顶部项目与堆中的最后一项交换:[2,4,5,1,3,6,7]
,减少计数,然后进行筛选:[5,4,2,1,3,6,7]
:
5
4 2
1 3
如果继续对堆中剩余的五个项目进行处理,最终会得到一个已排序的数组。
这个代码非常简单:
int count = array.length-1;
while (count > 0)
{
swap(array[0], array[count]);
--count;
siftDown(0);
}
如果要进行降序排序,可以使用max-heap执行上述操作,然后反转数组(O(1)操作),也可以构建一个min-heap来启动。
siftDown
方法只是按照二进制堆构造的规则将项目移动到适当的位置:
void siftDown(int index)
{
// Left child is at index*2+1. Right child is at index*2+2;
while (true)
{
// first find the largest child
int largestChild = index*2+1;
// if left child is larger than count, then done
if (largestChild >= count)
{
break;
}
// compare with right child
if (largestChild+1 < count && array[largestChild] < array[largestChild+1])
{
++largestChild;
}
// If item is smaller than the largest child, then swap and continue.
if (array[index] < array[largestChild])
{
swap(array[index], array[largestChild]);
index = largestChild;
}
else
{
break;
}
}