📜  从数组构建堆

📅  最后修改于: 2021-10-28 01:57:28             🧑  作者: Mango

给定一个包含 N 个元素的数组。任务是从给定的数组构建一个二叉堆。堆可以是最大堆或最小堆。

示例

Input: arr[] = {4, 10, 3, 5, 1}
Output: Corresponding Max-Heap:
       10
     /   \
    5     3
   /  \
  4    1

Input: arr[] = {1, 3, 5, 4, 6, 13, 10, 9, 8, 15, 17}
Output: Corresponding Max-Heap:
                 17
              /      \
            15         13
          /    \      /  \
         9      6    5   10
        / \    /  \
       4   8  3    1

假设给定的输入元素是:4, 10, 3, 5, 1。

这个元素数组 [4, 10, 3, 5, 1] 对应的完整二叉树将是:

4
     /   \
    10    3
   /  \
  5    1

Note:
Root is at index 0 in array.
Left child of i-th node is at (2*i + 1)th index.
Right child of i-th node is at (2*i + 2)th index.
Parent of i-th node is at (i-1)/2 index.

简单方法:假设,我们需要从上面给定的数组元素构建一个最大堆。可以明显看出,上面形成的完全二叉树并不遵循Heap属性。因此,我们的想法是按照自上而下的方法以相反的级别顺序堆化由数组形成的完整二叉树。

即首先堆化,树的层序遍历中的最后一个节点,然后堆化倒数第二个节点,依此类推。

时间复杂度: Heapify 单个节点的时间复杂度为 O(log N),其中 N 是节点总数。因此,构建整个 Heap 需要 N 个 heapify 操作,总时间复杂度为O(N*logN)

实际上,根据可以在此处看到的实现,构建堆需要 O(n) 时间。

优化方法:上述方法可以通过观察一个事实,即叶节点不需要被heapified因为他们已经跟随堆特性进行优化。此外,完整二叉树的数组表示包含树的层序遍历。

所以思路就是找到最后一个非叶子节点的位置,将每个非叶子节点的heapify操作逆级顺序进行。

Last non-leaf node = parent of last-node.
or, Last non-leaf node = parent of node at (n-1)th index.
or, Last non-leaf node = Node at index ((n-1) - 1)/2.
                       = (n/2) - 1.

插图

Array = {1, 3, 5, 4, 6, 13, 10, 9, 8, 15, 17}

Corresponding Complete Binary Tree is:
                 1
              /     \
            3         5
         /    \     /  \
        4      6   13  10
       / \    / \
      9   8  15 17

The task to build a Max-Heap from above array.

Total Nodes = 11.
Last Non-leaf node index = (11/2) - 1 = 4.
Therefore, last non-leaf node = 6.

To build the heap, heapify only the nodes:
[1, 3, 5, 4, 6] in reverse order.

Heapify 6: Swap 6 and 17.
                 1
              /     \
            3         5
         /    \      /  \
        4      17   13  10
       / \    /  \
      9   8  15   6

Heapify 4: Swap 4 and 9.
                 1
              /     \
            3         5
         /    \      /  \
        9      17   13  10
       / \    /  \
      4   8  15   6

Heapify 5: Swap 13 and 5.
                 1
              /     \
            3         13
         /    \      /  \
        9      17   5   10
       / \    /  \
      4   8  15   6

Heapify 3: First Swap 3 and 17, again swap 3 and 15.
                 1
              /     \
            17         13
          /    \      /  \
         9      15   5   10
        / \    /  \
       4   8  3   6

Heapify 1: First Swap 1 and 17, again swap 1 and 15, 
           finally swap 1 and 6.
                 17
              /      \
            15         13
          /    \      /  \
         9      6    5   10
        / \    /  \
       4   8  3    1

实施

C++
// C++ program for building Heap from Array
  
#include 
  
using namespace std;
  
// 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);
    }
}
  
// Function to build a Max-Heap from the given array
void buildHeap(int arr[], int n)
{
    // Index of last non-leaf node
    int startIdx = (n / 2) - 1;
  
    // Perform reverse level order traversal
    // from last non-leaf node and heapify
    // each node
    for (int i = startIdx; i >= 0; i--) {
        heapify(arr, n, i);
    }
}
  
// A utility function to print the array
// representation of Heap
void printHeap(int arr[], int n)
{
    cout << "Array representation of Heap is:\n";
  
    for (int i = 0; i < n; ++i)
        cout << arr[i] << " ";
    cout << "\n";
}
  
// Driver Code
int main()
{
    // Binary Tree Representation
    // of input array
    // 1
    //           /     \
    // 3         5
    //      /    \     /  \
    // 4      6   13  10
    //    / \    / \
    // 9   8  15 17
    int arr[] = { 1, 3, 5, 4, 6, 13, 10, 9, 8, 15, 17 };
  
    int n = sizeof(arr) / sizeof(arr[0]);
  
    buildHeap(arr, n);
  
    printHeap(arr, n);
    // Final Heap:
    // 17
    //           /      \
    // 15         13
    //       /    \      /  \
    // 9      6    5   10
    //     / \    /  \
    // 4   8  3    1
  
    return 0;
}


Java
// Java program for building Heap from Array
  
public class BuildHeap {
  
    // To heapify a subtree rooted with node i which is
    // an index in arr[].Nn is size of heap
    static 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) {
            int swap = arr[i];
            arr[i] = arr[largest];
            arr[largest] = swap;
  
            // Recursively heapify the affected sub-tree
            heapify(arr, n, largest);
        }
    }
  
    // Function to build a Max-Heap from the Array
    static void buildHeap(int arr[], int n)
    {
        // Index of last non-leaf node
        int startIdx = (n / 2) - 1;
  
        // Perform reverse level order traversal
        // from last non-leaf node and heapify
        // each node
        for (int i = startIdx; i >= 0; i--) {
            heapify(arr, n, i);
        }
    }
  
    // A utility function to print the array
    // representation of Heap
    static void printHeap(int arr[], int n)
    {
        System.out.println("Array representation of Heap is:");
  
        for (int i = 0; i < n; ++i)
            System.out.print(arr[i] + " ");
  
        System.out.println();
    }
  
    // Driver Code
    public static void main(String args[])
    {
        // Binary Tree Representation
        // of input array
        // 1
        //           /     \
        // 3         5
        //      /    \     /  \
        // 4      6   13  10
        //    / \    / \
        // 9   8  15 17
        int arr[] = { 1, 3, 5, 4, 6, 13, 10,
                      9, 8, 15, 17 };
  
        int n = arr.length;
  
        buildHeap(arr, n);
  
        printHeap(arr, n);
    }
}


Python3
# Python3 program for building Heap from Array
  
# To heapify a subtree rooted with node i 
# which is an index in arr[]. N is size of heap
def heapify(arr, n, i):
  
    largest = i; # Initialize largest as root
    l = 2 * i + 1; # left = 2*i + 1
    r = 2 * i + 2; # right = 2*i + 2
  
    # If left child is larger than root
    if l < n and arr[l] > arr[largest]:
        largest = l;
  
    # If right child is larger than largest so far
    if r < n and arr[r] > arr[largest]:
        largest = r;
  
    # If largest is not root
    if largest != i:
        arr[i], arr[largest] = arr[largest], arr[i];
  
        # Recursively heapify the affected sub-tree
        heapify(arr, n, largest);
  
# Function to build a Max-Heap from the given array
def buildHeap(arr, n):
  
    # Index of last non-leaf node
    startIdx = n // 2 - 1;
  
    # Perform reverse level order traversal
    # from last non-leaf node and heapify
    # each node
    for i in range(startIdx, -1, -1):
        heapify(arr, n, i);
  
# A utility function to print the array
# representation of Heap
def printHeap(arr, n):
    print("Array representation of Heap is:");
  
    for i in range(n):
        print(arr[i], end = " ");
    print();
  
# Driver Code
if __name__ == '__main__':
      
    # Binary Tree Representation
    # of input array
    # 1
    #         /     \
    # 3         5
    #     / \     / \
    # 4     6 13 10
    # / \ / \
    # 9 8 15 17
    arr = [ 1, 3, 5, 4, 6, 13, 
             10, 9, 8, 15, 17 ];
  
    n = len(arr);
  
    buildHeap(arr, n);
  
    printHeap(arr, n);
      
    # Final Heap:
    # 17
    #         /     \
    # 15         13
    #     / \     / \
    # 9     6 5 10
    #     / \ / \
    # 4 8 3 1
  
# This code is contributed by Princi Singh


C#
// C# program for building Heap from Array 
using System;
  
public class BuildHeap 
{ 
  
    // To heapify a subtree rooted with node i which is 
    // an index in arr[].Nn is size of heap 
    static 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) 
        { 
            int swap = arr[i]; 
            arr[i] = arr[largest]; 
            arr[largest] = swap; 
  
            // Recursively heapify the affected sub-tree 
            heapify(arr, n, largest); 
        } 
    } 
  
    // Function to build a Max-Heap from the Array 
    static void buildHeap(int []arr, int n) 
    { 
        // Index of last non-leaf node 
        int startIdx = (n / 2) - 1; 
  
        // Perform reverse level order traversal 
        // from last non-leaf node and heapify 
        // each node 
        for (int i = startIdx; i >= 0; i--) 
        { 
            heapify(arr, n, i); 
        } 
    } 
  
    // A utility function to print the array 
    // representation of Heap 
    static void printHeap(int []arr, int n) 
    { 
        Console.WriteLine("Array representation of Heap is:"); 
  
        for (int i = 0; i < n; ++i) 
            Console.Write(arr[i] + " "); 
  
        Console.WriteLine(); 
    } 
  
    // Driver Code 
    public static void Main() 
    { 
        // Binary Tree Representation 
        // of input array 
        // 1 
        //     / \ 
        // 3         5 
        // / \     / \ 
        // 4     6 13 10 
        // / \ / \ 
        // 9 8 15 17 
        int []arr = { 1, 3, 5, 4, 6, 13, 10, 
                    9, 8, 15, 17 }; 
  
        int n = arr.Length; 
  
        buildHeap(arr, n); 
  
        printHeap(arr, n); 
    } 
} 
  
// This code is contributed by Ryuga


输出:
Array representation of Heap is:
17 15 13 9 6 5 10 4 8 3 1

如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程学生竞争性编程现场课程