Java中的最大堆数据结构实现
最大堆是完整的二叉树,其中节点的值大于或者等于其子代的值。
Max Heap数据结构对于使用堆排序对数据进行排序非常有用。
在本教程中,我们将介绍从头开始在Java中实现最大堆所需的所有知识。
Java中最大堆数据结构的实现
我们使用数组表示堆。
由于堆是完整的二叉树,因此不会浪费空间。
例如,让我们考虑如下的堆:
数组表示为:
最大堆的声明如下:
static class MaxHeap { private int[] Heap; //array private int size; private int maxsize; public MaxHeap(int size) { this.maxsize = size; this.size = 0; Heap = new int[this.maxsize + 1]; Heap[0] = Integer.MAX_VALUE; }
堆是存储最大堆的数组。
构造函数采用大小并将数组的第0个元素初始化为无穷大。
我们从索引1开始我们的堆。
1.获取节点的父节点
由于我们将堆存储为数组,因此获取节点的父节点变得更加容易。
对于位于位置i的元素,其父元素的位置由给出:
(i)/2
在实现过程中,我们可以使用以下方法获取父项:
private int parent(int pos) { return pos/2; }
2.为节点获取子代
对于位置i处的节点,其子级由以下公式给出:
左孩子:
(2*i)
合适的孩子:
(2*i)+ 1
注意:当堆从索引1开始时,这是正确的。
如果堆从位置0开始,则左子对象和右子对象的值分别为(2 * i)+1和(2 * i)+2。
在代码中,我们如下实现:
private int leftChild(int pos) { return (2 * pos) ; } private int rightChild(int pos) { return (2 * pos) + 1; }
3.堆新插入的元素
将元素插入堆后,它可能不满足堆属性。
在这种情况下,我们需要调整堆的位置以使其再次成为堆。
此过程称为堆整。
要在最大堆中堆积一个元素,我们需要找到其最大子元素并将其与当前元素交换。
我们继续此过程,直到每个节点上的heap属性都满足为止。
为了堆积,我们从根部向下移动到叶子。
因此,这也称为Down Heapify。
另一个需要注意的有趣点是,我们仅在非叶节点上执行down heapify。
下堆函数的代码是:
private void downHeapify(int pos) { //checking if the node is a leaf node if (pos >= (size/2) && pos <= size) return; //checking if a swap is needed if (Heap[pos] < Heap[leftChild(pos)] || Heap[pos] < Heap[rightChild(pos)]) { //replacing parent with maximum of left and right child if (Heap[leftChild(pos)] > Heap[rightChild(pos)]) { swap(pos, leftChild(pos)); //after swaping, heapify is called on the children downHeapify(leftChild(pos)); } else { swap(pos, rightChild(pos)); //after swaping, heapify is called on the children downHeapify(rightChild(pos)); } } }
交换函数如下:
private void swap(int fpos, int spos) { int tmp; tmp = Heap[fpos]; Heap[fpos] = Heap[spos]; Heap[spos] = tmp; }
您也可以使用while循环而不是递归来编写相同的代码。
在低调处理中,我们从父母转向孩子。
我们也可以采用自下而上的方式。
当我们以自下而上的方式移动时,我们会将节点与其父节点进行比较。
这称为Up Heapify。
大堆代码是:
private void heapifyUp(int pos) { int temp = Heap[pos]; while(pos>0 && temp > Heap[parent(pos)]){ Heap[pos] = Heap[parent(pos)]; pos = parent(pos); } Heap[pos] = temp; }
我们使用while循环而不是递归编写了up heapify的代码。
4.插入新节点
将新元素添加到数组的末尾,并执行交换以确保堆属性成立。
插入算法为:
- 增加堆大小
- 将新元素保留在堆的末尾(数组)
- 从下到上堆砌
插入的代码是:
public void insert(int element) { Heap[++size] = element; int current = size; heapifyUp(current); }
5.删除/提取节点
要从堆中删除/提取节点,我们从根中删除元素。
根始终提供最大元素。
删除算法如下:
将第一个元素复制到变量中。
将最后一个元素复制到第一个位置(根)。
调用downHeapify()。
删除的代码是:
public int extractMax() { int max = Heap[1]; Heap[1] = Heap[size--]; downHeapify(1); return max; }
其中我们使用size–减小堆的大小。
Java中Max Heap的完整实现
Max Heap的完整java实现如下。
package com.theitroad; public class Main { static class MaxHeap { private int[] Heap; private int size; private int maxsize; public MaxHeap(int size) { this.maxsize = size; this.size = 0; Heap = new int[this.maxsize + 1]; Heap[0] = Integer.MAX_VALUE; } private int parent(int pos) { return pos/2; } private int leftChild(int pos) { return (2 * pos) ; } private int rightChild(int pos) { return (2 * pos) + 1; } private void swap(int fpos, int spos) { int tmp; tmp = Heap[fpos]; Heap[fpos] = Heap[spos]; Heap[spos] = tmp; } private void downHeapify(int pos) { if (pos >= (size/2) && pos <= size) return; if (Heap[pos] < Heap[leftChild(pos)] || Heap[pos] < Heap[rightChild(pos)]) { if (Heap[leftChild(pos)] > Heap[rightChild(pos)]) { swap(pos, leftChild(pos)); downHeapify(leftChild(pos)); } else { swap(pos, rightChild(pos)); downHeapify(rightChild(pos)); } } } private void heapifyUp(int pos) { int temp = Heap[pos]; while(pos>0 && temp > Heap[parent(pos)]){ Heap[pos] = Heap[parent(pos)]; pos = parent(pos); } Heap[pos] = temp; } public void insert(int element) { Heap[++size] = element; int current = size; heapifyUp(current); } public void print() { for (int i = 1; i <= size/2; i++) { System.out.print(+ Heap[i] + ": L- " + Heap[2 * i] + " R- " + Heap[2 * i + 1]); System.out.println(); } } public int extractMax() { int max = Heap[1]; Heap[1] = Heap[size--]; downHeapify(1); return max; } } public static void main(String[] arg) { MaxHeap maxHeap = new MaxHeap(15); maxHeap.insert(1); maxHeap.insert(4); maxHeap.insert(2); maxHeap.insert(5); maxHeap.insert(13); maxHeap.insert(6); maxHeap.insert(17); maxHeap.print(); System.out.println("The max is " + maxHeap.extractMax()); } }
Output : 17: L- 5 R- 13 5: L- 1 R- 4 13: L- 2 R- 6 The max is 17