前言
二叉堆是一颗完全二叉树,并满足堆中某个节点的值总是小于或等于父节点的值;

最大堆:根节点元素最大值;
最小堆:根节点元素最小值;
代码实现
基于数组实现最大二叉堆
- 自定义动态数组
package com.sjgd.heap;
/**
* 自定义动态数组
*/
public class Array<E> {
/**
* 维护的数组
*/
private E[] data;
/**
* 数组中元素的个数
*/
private int size;
public Array(int capacity) {
data = (E[]) new Object[capacity];
size = 0;
}
public Array(E[] arr) {
data = (E[]) new Object[arr.length];
System.arraycopy(arr, 0, data, 0, arr.length);
size = arr.length;
}
public Array() {
this(10);
}
/**
* 获取数组的融了
*
* @return
*/
public int getCapacity() {
return data.length;
}
/**
* 获取数组中元素的个数
*
* @return
*/
public int getSize() {
return size;
}
/**
* 判断数组是否为空
*
* @return
*/
public boolean isEmpty() {
return size == 0;
}
/**
* 在数组的index索引插入一个新的元素
*/
public void add(int index, E e) {
if (index < 0 || index > size) {
throw new IllegalArgumentException("Add Failed, Require index >=0 and index <= size");
}
if (size == data.length) {
//说明当前数组已满,需要进行扩容
resize(2 * data.length);
}
//索引位置后面的元素都需要往后移1个位置
for (int i = size - 1; i >= index; i--) {
data[i + 1] = data[i];
}
data[index] = e;
size++;
}
/**
* 向一个位置添加元素E
*/
public void addFirst(E e) {
add(0, e);
}
/**
* 向最后一个位置添加元素E
*
* @param e
*/
public void addLast(E e) {
add(size, e);
}
/**
* 根据index获取索引对应的元素E
*
* @param index
* @return
*/
public E get(int index) {
if (index < 0 || index >= size) {
throw new IllegalArgumentException("Get Failed, Index is illegal!");
}
return data[index];
}
/**
* 交换数组中两个元素的位置
*/
public void swap(int i, int j) {
if (i < 0 || i >= size || j < 0 || j >= size) {
throw new IllegalArgumentException("The Index is not Illegal");
}
E e = data[i];
data[i] = data[j];
data[j] = e;
}
/**
* 修改index索引位置对应的元素
*
* @param index
* @param e
*/
public void set(int index, E e) {
if (index < 0 || index >= size) {
throw new IllegalArgumentException("Add Failed, Require index >=0 and index <= size");
}
data[index] = e;
}
/**
* 判断当前数组是否包含元素E
*
* @param e
* @return
*/
public boolean contains(E e) {
for (int i = 0; i < size; i++) {
if (data[i].equals(e)) {
return true;
}
}
return false;
}
/**
* 查询元素E对应的下标位置
*
* @param e
* @return
*/
public int find(E e) {
for (int i = 0; i < size; i++) {
if (data[i].equals(e)) {
return i;
}
}
return -1;
}
public E remove(int index) {
if (index < 0 || index >= size) {
throw new IllegalArgumentException("remove Failed, Require index >=0 and index < size");
}
E ret = data[index];
//从删除索引位置之后元素均向前移一位
for (int i = index + 1; i < size; i++) {
data[i - 1] = data[i];
}
size--;
//进行空间释放
data[size] = null;
//当数组元素到容量1/4时,进行缩容操作
if (size == data.length / 4 && data.length / 2 != 0) {
resize(data.length / 2);
}
return ret;
}
/**
* 移除第一个元素
*
* @return
*/
public E removeFirst() {
return remove(0);
}
/**
* 移除最后一个元素
*
* @return
*/
public E removeLast() {
return remove(size - 1);
}
/**
* 移除对应元素e
*
* @param e
*/
public void removeElement(E e) {
int index = find(e);
if (index != -1) {
remove(index);
}
}
@Override
public String toString() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(String.format("Array size=%d, capacity=%d\n", size, data.length));
stringBuilder.append("[");
for (int i = 0; i < size; i++) {
stringBuilder.append(data[i]);
if (i != size - 1) {
stringBuilder.append(",");
}
}
stringBuilder.append("]");
return stringBuilder.toString();
}
/**
* 对数组进行动态扩容或缩容
*
* @param newCapacity
*/
private void resize(int newCapacity) {
E[] newData = (E[]) new Object[newCapacity];
for (int i = 0; i < size; i++) {
newData[i] = data[i];
}
data = newData;
}
}
- 实现最大二叉堆
package com.sjgd.heap;
/**
* 基于数组实现最大堆
* on 2023/2/8
*/
public class MaxHeap<E extends Comparable<E>> {
private Array<E> array;
public MaxHeap(int capacity) {
array = new Array<>(capacity);
}
public MaxHeap() {
array = new Array<>();
}
public MaxHeap(E[] arr) {
array = new Array<>(arr);
for (int i = parent(array.getSize() - 1); i >= 0; i--) {
siftDown(i);
}
}
/**
* 返回堆中元素的个数
*
* @return
*/
public int size() {
return array.getSize();
}
/**
* 返回一个布尔值,判断当前堆是否为空
*
* @return
*/
public boolean isEmpty() {
return array.isEmpty();
}
/**
* 返回完全二叉树的数组表示中,一个索引所表示的元素的父节点所有的索引
*
* @return
*/
private int parent(int index) {
if (index == 0) {
throw new IllegalArgumentException("index 0 doesn't have parent.");
}
return (index - 1) / 2;
}
/**
* 返回完全二叉树的数组表示中,一个索引所表示的元素的左孩子节点的索引
*
* @return
*/
private int leftChild(int index) {
return index * 2 + 1;
}
/**
* 返回完全二叉树的数组表示中,一个索引所表示的元素的右孩子节点的索引
*
* @return
*/
private int rightChild(int index) {
return index * 2 + 2;
}
/**
* 往最大堆中添加元素e
*
* @param e
*/
public void add(E e) {
array.addLast(e);
siftUp(array.getSize() - 1);
}
public E removeMax() {
E result = getMax();
//先交换最大值和最后一个元素的位置
array.swap(0, array.getSize() - 1);
//删除最后一个元素
array.removeLast();
siftDown(0);
return result;
}
public E getMax() {
if (array.getSize() == 0) {
throw new IllegalArgumentException("The MaxHeap is Empty!");
}
return array.get(0);
}
/**
* 取出堆中最大元素,并替换成元素e
*
* @return
*/
public E replace(E e) {
E result = getMax();
array.set(0, e);
siftDown(0);
return result;
}
/**
* 不断与左右子节点中较大的比较并交换,直到满足最大堆要求;
*
* @param index
*/
private void siftDown(int index) {
while (leftChild(index) < array.getSize()) {
int leftChildIndex = leftChild(index);
int rightChildIndex = leftChildIndex + 1;
if (rightChildIndex < array.getSize() && array.get(leftChildIndex).compareTo(array.get(rightChildIndex)) < 0) {
leftChildIndex = rightChildIndex;
}
if (array.get(index).compareTo(array.get(leftChildIndex)) > 0) {
break;
}
array.swap(index, leftChildIndex);
index = leftChildIndex;
}
}
/**
* 不断与父节点元素进行对比,如果大于父节点元素不断交换两者位置,直到满足最大堆要求;
*
* @param index
*/
private void siftUp(int index) {
while (index > 0 && array.get(index).compareTo(array.get(parent(index))) > 0) {
array.swap(index, parent(index));
index = parent(index);
}
}
}
- 基于
MaxHeap实现优先级队列;
package com.sjgd.heap;
/**
* @author 基于MaxHeap实现优先级队列
* on 2023/2/8
*/
public class PriorityQueue<E extends Comparable<E>> implements Queue<E> {
private MaxHeap<E> maxHeap;
public PriorityQueue() {
maxHeap = new MaxHeap<>();
}
@Override
public int getSize() {
return maxHeap.size();
}
@Override
public boolean isEmpty() {
return maxHeap.isEmpty();
}
@Override
public void enqueue(E e) {
maxHeap.add(e);
}
@Override
public E dequeue() {
return maxHeap.removeMax();
}
@Override
public E getFront() {
return maxHeap.getMax();
}
}
时间复杂度
入队出队:O(logn)
结语
如果以上文章对您有一点点帮助,希望您不要吝啬的点个赞加个关注,您每一次小小的举动都是我坚持写作的不懈动力!ღ( ´・ᴗ・` )
文章介绍了如何使用Java自定义动态数组实现最大二叉堆,包括插入、删除、查找等操作,并基于最大堆构建了优先级队列,讨论了相关的时间复杂度。
5284

被折叠的 条评论
为什么被折叠?



