从堆中删除随机元素

时间:2016-10-19 02:54:22

标签: java algorithm data-structures heap clrs

我读了一些文章说,在堆中,只能删除根元素。但是,为什么我们不能使用以下方法删除元素?

  1. 查找要删除的关键元素的索引
  2. 将此元素与最后一个元素交换,因此该键成为最后一个元素
  3. 从密钥的原始索引(现在已与最后一个元素交换)开始重新堆积。
  4. 将堆的大小减少1
  5. 因此,代码看起来像

    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);
            }
        }
    

3 个答案:

答案 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下,以维护堆属性。
  • 返回存储的变量。 资料来源-GeeksforGeeks。

答案 2 :(得分:-2)

堆的根有一个与所有其他元素相关的属性。删除根时,只有一个其他元素将满足该条件,该条件不会(可能)是您要删除的元素。因此,交换元素将使堆具有非确定性结果。