我做了一堆。如果我的删除功能出现了一些微妙的错误,我很好奇:
int Heap::remove() {
if (n == 0)
exit(1);
int temp = arr[0];
arr[0] = arr[--n];
heapDown(0);
arr[n] = 0;
return temp;
}
void Heap::heapDown(int i)
{
int l = left(i);
int r = right(i);
// comparing parent to left/right child
// each has an inner if to handle if the first swap causes a second swap
// ie 1 -> 3 -> 5
// 3 5 1 5 1 3
if (l < n && arr[i] < arr[l])
{
swap(arr[i], arr[l]);
heapDown(l);
if (r < n && arr[i] < arr[r])
{
swap(arr[i], arr[r]);
heapDown(r);
}
}
else if (r < n && arr[i] < arr[r])
{
swap(arr[i], arr[r]);
heapDown(r);
if (l < n && arr[i] < arr[l])
{
swap(arr[i], arr[l]);
heapDown(l);
}
}
}
这是我的输出
i1i2i3i4i5i6i7
p
Active heap: 7 4 6 1 3 2 5
r
Removed 7
r
Removed 6
p
Active heap: 5 3 4 1 2
这是我老师的样本输出:
p
Active heap : 7 4 6 1 3 2 5
r
Removed 7
r
Removed 6
p
Active heap : 5 4 2 1 3
s
Heapsorted : 1 2 3 4 5
虽然我们的输出是完全不同的,但我似乎确实保持了最大化的原则,即所有节点都是朝向所有节点的父节点&gt;孩子(在每种情况下我都试过)。我尝试从头开始做这样的algs,所以也许我只是做了一些非常奇怪和错误的事情(如果它是&gt; O(lg n),我只会认为它是“错误的”,因为删除是为了堆) 。我的删除有什么特别“错误”吗?谢谢,
答案 0 :(得分:3)
首先,我假设您的意思是除了您不需要它之外,因为我们在C ++标准库中设置了整个堆管理功能,包括make_heap,push_heap,pop_heap甚至sort_heap。
那就是说,我想我知道你的问题是什么。您的堆中有不必要的元素移动。它处理堆上的交换算法:同样的问题在左侧和右侧都是值得注意的,所以我将展示第一个:
if (l < n && arr[i] < arr[l])
{
swap(arr[i], arr[l]);
heapDown(l);
if (r < n && arr[i] < arr[r])
{
swap(arr[i], arr[r]);
heapDown(r);
}
}
此处的逻辑对于最小运动不是最佳的。被推下的元素的“较小”状态必须属于两个基本类别之一,并且每个类别都采取不同的行动:
该列表中的#2是代码中的问题。你交换较小的,然后更大的,如果项目&lt;左&lt;对。我希望这很清楚。如果你想要一个提议来修复你的逻辑,我可以提供一个,但我想如果你理解我上面描述的内容你就可以掌握它。
<强>扰流强>
void Heap::heapDown(int i)
{
int l = left(i);
int r = right(i);
int x = 0;
if (l < n && arr[i] < arr[l])
{
x = l;
if (r < n && arr[l] < arr[r])
x = r;
}
else if (r < n && arr[i] < arr[r])
x = r;
if (x != 0)
{
swap(arr[i], arr[x]);
heapDown(x);
}
}
请注意:;如果不明显,这就是尾递归的定义,因此可以很容易地转换成一个简单的迭代循环。