【问题标题】:When building heap, is heap unique?建堆时,堆是唯一的吗?
【发布时间】:2015-08-13 16:32:51
【问题描述】:

我正在研究堆和堆排序。
有一个数组:arr[8] = {6,9,3,1,8,7,2,11}
当我尝试使用代码和铅笔构建堆时,我遇到了两种堆。

使用代码时, 最大堆:11 9 7 6 8 3 2 1

使用插入理论时,MaxHeap : 11 9 7 8 6 3 2 1


我正在使用的代码:

int[] DoHeapSort(int[] value) {
    int length = value.length;

    for (int i = length / 2; i > 0; i--) {
        maxHeapify(value, i, length);
    }

    //print Heap
    for(int i = 0 ; i<value.length; i++)
        System.out.println(value[i]);

    return (value);
}


void maxHeapify(int[] array, int index, int heapSize) {
    int left = index * 2;
    int right = left + 1;
    int max = index;

    if (left <= heapSize && array[left - 1] > array[index - 1]) {
        max = left;
    }

    if (right <= heapSize && array[right - 1] > array[max - 1]) {
        max = right;
    }

    if (max != index) {
        swap(array, index - 1, max - 1);
        maxHeapify(array, max, heapSize);
    }
}

理论上,在这种情况下,为堆创建另一个数组并按顺序从 6 插入到 11。 (另一方面,代码是就地堆)

两个 maxHeap 结果都满足堆定义。那么堆不是唯一的吗?谢谢

【问题讨论】:

    标签: algorithm data-structures heap


    【解决方案1】:

    没错。堆约束(即子级不大于父级)并没有完全指定堆,因此通常有不止一种可能的排列方式。

    【讨论】:

    • @user3595632:我会使用 O(n) 就地算法。这是通常的实现方式。
    • @user3595632: 来自二进制堆上的维基百科:“然而,在 1974 年,Thomas Porter 和 Istvan Simon 证明了插入节点向上移动的平均层数的函数是有上限的由常数 1.6067. ... 因此,平均而言,二进制堆插入具有常数 O(1) 时间复杂度。“链接:en.wikipedia.org/wiki/Binary_heap#Insert
    • @PieterGeerkens:这很有趣,但没有解决最坏的情况。但是,如果您在该 wikipedia 文章中稍微阅读一下,您会遇到一个更简单的证明,即如果您正确地进行构建,构建堆是最坏情况 O(n)(相反迭代地插入每个元素,这是最坏的情况 O(n log n) )
    • @user3595632:正是因为堆没有完全确定,所以可以在最坏情况下构建它 O(n)。从堆中提取排序后的序列是 O(n log n)。
    • @PieterGeerkens:这当然是一个有趣的事实!但我猜 Porter 和 Simon 使用的“平均”概念是基于给定大小的所有可能堆上的概率分布(例如,大小为 n 的堆上的均匀分布),而不是所有可能的序列堆上的插入,否则使用普通插入来构建堆也会产生摊销的 O(n) 最坏情况时间——对吧?
    【解决方案2】:

    考虑项目{1, 2, 3}。最大堆有两种有效的安排:

        3              3
      /   \          /   \
     1     2        2     1
    
    {3, 1, 2}      {3, 2, 1}
    

    这两个都满足有效最大堆的必要条件。

    给定一个完整的堆(即所有级别都已满),您可以交换任何节点的子节点并且仍然有一个有效的堆。或者,更一般地说,只要您保持 shape 属性,您就可以交换任何节点的子节点。

    请注意,“交换子项”是指交换锚定在该子项上的整个子树。

    除了交换子节点之外,您还可以重新排列节点。

    例如,考虑这个最大堆:

          10
        /    \
       9      8
      / \    / \
     7   6  5   4
    

    最后一层节点的顺序无关;任何一个叶节点都可以是 8 或 9 的子节点。这四个子节点有 24 种可能的排列。

    其他安排也是可能的。例如:{10,9,6,7,8,5,4}

    您获得哪种安排取决于您的插入和删除算法的具体情况,以及插入和删除的顺序。或者,在从数组构建堆的情况下(即 O(n) 方法),开始时数组中的项目顺序。

    【讨论】:

      猜你喜欢
      • 2020-09-02
      • 2011-06-05
      • 2021-04-21
      • 1970-01-01
      • 2019-11-27
      • 2017-08-18
      • 2015-10-11
      • 2016-03-20
      • 1970-01-01
      相关资源
      最近更新 更多