目录
堆的基本概念:
如何将一个二叉树调整成一个大根堆:
转成大根堆的时间复杂度
根堆中的插入,取出数据:
堆的基本概念:
堆是一种特殊的树形数据结构,它满足以下两个性质:
- 堆是一个完全二叉树,即除了最后一层外,其他层都是满的,并且最后一层的节点都尽量靠左排列。
- 堆中每个节点的值都大于等于(或小于等于)其子节点的值,根节点的值最大(或最小)。
根据第二个性质,堆可以分为最大堆和最小堆:
- 最大堆:每个节点的值都大于等于其子节点的值,根节点的值最大。(又称大根堆)
- 最小堆:每个节点的值都小于等于其子节点的值,根节点的值最小。(又称小根堆)
堆通常用于实现优先队列,可以高效地插入、删除和获取具有最高(或最低)优先级的元素。常见的堆有二叉堆、斐波那契堆等。
如何将一个二叉树调整成一个大根堆:
要将一个二叉树调整成一个大根堆,可以采用堆排序的思想,从最后一个非叶子节点开始,依次向上调整每个节点,使其满足大根堆的性质。以下是一个示例的Java代码实现:
class MaxHeap { public void heapify(int[] arr) { int n = arr.length; // 从最后一个非叶子节点开始向上调整 for (int i = n / 2 - 1; i >= 0; i--) { heapifyUtil(arr, n, i); } } private void heapifyUtil(int[] arr, int n, int i) { int largest = i; // 初始化最大值为当前节点 int left = 2 * i + 1; int right = 2 * i + 2; // 找出当前节点、左子节点和右子节点中的最大值 if (left < n && arr[left] > arr[largest]) { largest = left; } if (right < n && arr[right] > arr[largest]) { largest = right; } // 如果最大值不是当前节点,则交换位置并递归调整 if (largest != i) { int temp = arr[i]; arr[i] = arr[largest]; arr[largest] = temp; heapifyUtil(arr, n, largest); } } }
假设我们有一个数组
arr = {4, 10, 3, 5, 1}
,我们希望将其调整成一个大根堆。我们可以使用上面提供的MaxHeap
类中的heapify()
方法来实现。public class Main { public static void main(String[] args) { int[] arr = {4, 10, 3, 5, 1}; MaxHeap maxHeap = new MaxHeap(); maxHeap.heapify(arr); System.out.println("大根堆数组:"); for (int num : arr) { System.out.print(num + " "); } } }
在上面的示例中,我们将数组
{4, 10, 3, 5, 1}
调整成大根堆后,输出结果应该为{10, 5, 3, 4, 1}
。
调成小根堆同理。
转成大根堆的时间复杂度
在将一个数组调整成大根堆的过程中,我们从最后一个非叶子节点开始,依次向上调整每个节点,使得每个节点都满足大根堆的性质。
从最后一个非叶子节点开始,向上遍历直到根节点。对于一个具有n个节点的完全二叉树,最后一个非叶子节点的索引为n/2 - 1。
在每个节点处,我们需要执行以下操作:
- 比较当前节点与其左右子节点的值,找出其中最大的值。
- 如果最大值不是当前节点的值,则交换当前节点与最大子节点的值。
- 继续向下递归调整交换后的子节点,直到满足大根堆的性质。
因为每个节点最多需要比较和交换O(log n)次,而最后一个非叶子节点的数量是n/2,所以整个调整过程的时间复杂度为O(n)。
因此,将一个数组调整成大根堆的时间复杂度为O(n)。
根堆中的插入,取出数据:
如果您想在 Java 中实现向大根堆中插入元素和从大根堆中取出最大元素的操作,您可以修改
MaxHeap
类,添加insert()
和extractMax()
方法。下面是一个示例代码:public class MaxHeap { public void heapify(int[] arr) { int n = arr.length; for (int i = n / 2 - 1; i >= 0; i--) { heapifyUtil(arr, n, i); } } private void heapifyUtil(int[] arr, int n, int i) { int largest = i; int left = 2 * i + 1; int right = 2 * i + 2; if (left < n && arr[left] > arr[largest]) { largest = left; } if (right < n && arr[right] > arr[largest]) { largest = right; } if (largest != i) { int temp = arr[i]; arr[i] = arr[largest]; arr[largest] = temp; heapifyUtil(arr, n, largest); } } public void insert(int[] arr, int key) { // 将新元素插入到数组末尾 arr[arr.length] = key; // 从新元素的父节点开始向上调整 int i = arr.length; while (i > 0 && arr[(i-1)/2] < arr[i]) { int temp = arr[i]; arr[i] = arr[(i-1)/2]; arr[(i-1)/2] = temp; i = (i-1)/2; } } public int extractMax(int[] arr) { int n = arr.length; if (n == 0) { return -1; // 堆为空 } int max = arr[0]; // 最大元素为根节点 arr[0] = arr[n-1]; // 将最后一个元素移到根节点 heapifyUtil(arr, n-1, 0); // 从根节点开始向下调整 return max; } }