如何建立堆树?

时间:2018-10-02 01:17:44

标签: algorithm sorting heapsort

我了解构建堆树(最大或最小)的算法,但我不了解其代码:

首先:此循环如何建立最大堆?为什么我们以n / 2-1开头i?

// Build heap (rearrange array) 
for (int i = n / 2 - 1; i >= 0; i--) 
    heapify(arr, n, i); 

这是Heapify函数:

第二:我们如何假定最大的是“ i”?

第三条:为什么我们在最后一行再次进行堆积?

// To heapify a subtree rooted with node i which is 
// an index in arr[]. n is size of heap 
void heapify(int arr[], int n, int i) 
{ 
    int largest = i; // Initialize largest as root 
    int l = 2*i + 1; // left = 2*i + 1 
    int r = 2*i + 2; // right = 2*i + 2 

    // If left child is larger than root 
    if (l < n && arr[l] > arr[largest]) 
        largest = l; 

    // If right child is larger than largest so far 
    if (r < n && arr[r] > arr[largest]) 
        largest = r; 

    // If largest is not root 
    if (largest != i) 
    { 
        swap(arr[i], arr[largest]); 

        // Recursively heapify the affected sub-tree 
        heapify(arr, n, largest); 
    } 
} 

我得到的代码和算法来自GeeksForGeeks

3 个答案:

答案 0 :(得分:2)

1)考虑堆结构

              M
       K            L
   G       H     I     J  
 A  B    C  D   E  F  

最后一层最多包含所有项目的一半((n+1)//2),因此索引n/2-1上的项目始终是最后一层的最后一项的父项。然后从该索引开始,向左遍历,我们订购了三个项目的迷你堆,然后向上和向左遍历,我们订购了7个项目的堆,等等。

2)这是条件任务的简单初始化-如果我们发现较大的后代,它将替换父级

3)如果父代已被替换,它会向下移动,并且可能小于新的后代,因此我们必须检查(小元素沉没)

答案 1 :(得分:1)

让我们用一个非常简单的示例来建立一个最大堆来做到这一点,我认为它将回答您的问题。假设您有一个数组[3, 1, 6, 4, 7, 9]。对应于此二叉树:

     3
  1     6
4   7 9

该算法的思想是将事物向下推到适当位置。您的第一个问题是为什么我们从i = n//2开始。一个简单的答案是,位置大于i // 2的任何节点都是叶子。它没有孩子,因此不能被压低。实际上,我们可以从(n-1)//2开始,因为如果n是偶数,则第一个非叶子节点在那里,对于奇数,(n-1)//2 == n/2

因此,在这种情况下,i=2。您的下一个问题是,为什么我们假设索引i处的元素最大。我们没有。我们从此开始,因为我们必须找到这三个项目中的最大项目(i中的项目及其两个孩子)。所以我们只是默认为i。您可以根据需要将largest设置为左孩子,然后进行比较。但是没有这样做的特殊理由。您必须从 something 开始,索引为i的项目最简单。

在这种情况下,索引为i的项为6。我们检查了该项的子项,发现9大,因此我们进行交换。结果是:

     3
  1     9
4   7 6

我们递减i,给我们i=1。查看那里的项目及其子项,我们看到7是最大的项目,因此我们交换了两个项目,得出:

     3
  7     9
4   1 6

现在我们已经扎根。 9是根及其子节点中最大的,因此我们交换:

     9
  7     3
4   1 6

这是您第三个问题的答案:为什么递归调用heapify?您必须将项目向下推到堆的最远处。在这里,3小于6,因此我们必须交换这些项以得出:

     9
  7     6
4   1 3

答案 2 :(得分:0)

父节点的最大子索引ci为:

ci = 2*i + 2 < size
i < (size - 2)/2
i < size/2 - 1

但是您需要包括size/2 - 1,因为一个节点可能只有一个孩子,而i一直到零,因为所有这些节点都是父节点。至于递归,您需要在交换后执行max-heap规则。