我读了一些文章说,在堆中,只能删除根元素。但是,为什么我们不能使用以下方法删除元素?
因此,代码看起来像
static void delete(int[] a, int key)
{
int i = 0;
for(i = 0;i<a.length;i++)
{
if(a[i] == key)
break;
}
swap(a, i, a.length-1);
max_heapify_forheapsort(a, i, a.length-2);
}
static void max_heapify_forheapsort(int[] a, int i, int limit)
{
int left = (2*i)+1;
int right = (2*i) + 2;
int next = i;
if(left <= limit && a[left] > a[i])
next = left;
if(right <= limit && a[right] > a[next] )
next = right;
if(next!=i)
{
swap(a, next, i);
max_heapify_forheapsort(a, next, limit);
}
}
答案 0 :(得分:8)
根据您的建议,当然可以通过筛选或筛选操作从堆中删除元素。 (同样可以更改堆中任何项的键,并使用sift-up或-down操作来恢复堆属性。)
棘手的一点就是你在一开始就说的很快:&#34;找到索引。&#34;一个简单的实现需要O(n)来执行此操作,并且这会导致堆效率降低。当他们说'#34;你不能删除&#34;这是一个天真的实现,你无法有效删除。
幸运的是,找到索引O(1)并不难。只需保持一个反向地图&#34;与堆数组并行,例如从对象到堆数组索引的哈希映射。在不向任何堆操作添加渐近复杂性的情况下更新此映射很容易,并且使用它 - 正如您所指出的 - 删除具有复杂度O(log n)。向上/向下筛选主导地图查找以找到索引。
如果您对经过测试的实现感兴趣,here's one其中堆包含指向另一个对象数组的索引。因此,反向映射实现为数组variables.isVariable(readIn.substring(i))
,它是包含q->locs[k]
(它是对象表的索引)的堆元素的索引。
计算机科学中的许多问题都可以通过增加一个间接层来解决!
修改强>
由于OP询问为什么可能需要删除筛选,请考虑最小堆
k
我们要删除30,所以将4(最后一个数组元素)移动到它的位置:
1
20 2
30 40 3 4
显然需要筛选。
答案 1 :(得分:0)
如果是Minheap
,
Heapify
扎根。Heapify
下,以维护堆属性。答案 2 :(得分:-2)
堆的根有一个与所有其他元素相关的属性。删除根时,只有一个其他元素将满足该条件,该条件不会(可能)是您要删除的元素。因此,交换元素将使堆具有非确定性结果。