“堆”是一种特殊的二叉树,分为大顶堆:堆顶元素为最大值,子节点小于父节点;小顶堆:堆顶元素为最小值,子节点小于父节点。同时堆是一种完全二叉树,一定要·左右两个子节点都有了才能在子节点上插入子节点。
下面是堆的实现:
import lombok.Data;
@Data
public class Heap
{
private int[] arr;//数组,用于存储堆中的元素
private int size;//堆中元素的数量
private boolean isMaxHeap = true;//是否是大顶堆,默认为大顶堆
/**
* 构造函数,用于创建指定容量的空堆
* @param capacity 堆的容量
* @param isMaxHeap 是否是大顶堆
*/
public Heap(final int capacity,final boolean isMaxHeap)
{
arr = new int[capacity];//初始化数组
this.isMaxHeap = isMaxHeap;
}
public Heap(final int capacity)
{
arr = new int[capacity];//初始化数组
}
/**
* 构造函数,用于将指定数组转换为堆
* @param arr 数组
* @param isMaxHeap 是否是大顶堆
*/
public Heap(final int[] arr,final boolean isMaxHeap)
{
this.arr = arr;
this.size = arr.length;
this.isMaxHeap = isMaxHeap;
heapify();
}
public Heap(final int[] arr)
{
this.arr = arr;
this.size = arr.length;
heapify();
}
/**
* 建堆
*/
private void heapify()
{
//找到非叶子节点 size / 2 - 1
for (int i = size / 2 - 1; i >= 0; i --)
{
down(i);
}
}
/**
*获取堆顶元素
* @return 堆顶元素
*/
public Integer peek()
{
return isEmpty() ? null : arr[0];
}
/**
* 删除堆顶元素
* @return 堆顶元素
*/
public Integer poll()
{
if (isEmpty())
{
return null;
}
int top = arr[0];
swap(0,-- size);
down(0);
return top;
}
/**
* 删除指定索引处元素
* @param index 索引
* @return 堆顶元素
*/
public Integer poll(final int index)
{
if (isEmpty())
{
return null;
}
int e = arr[index];
swap(index,-- size);
down(index);
return e;
}
/**
* 替换堆顶元素
* @param replaced 替换的元素
*/
public void replace(final int replaced)
{
arr[0] = replaced;
down(0);
}
/**
* 向堆中添加元素
* @param offered 待添加的元素
*/
public boolean offer(final int offered)
{
if (isFull())
{
return false;
}
up(offered);//添加到堆尾,然后符合条件就上浮
size ++;
return true;
}
/**
* 上浮
* @param offered 待添加的元素
*/
public void up(final int offered)
{
int child = size;
while (child > 0)
{
int parent = (child - 1) / 2;
if (isMaxHeap)//大顶堆
{
if (offered > arr[parent])
{
arr[child] = arr[parent];
}
else
{
break;
}
}
else//小顶堆
{
if (offered < arr[parent])
{
arr[child] = arr[parent];
}
else
{
break;
}
}
child = parent;
}
arr[child] = offered;
}
/**
* 下沉
* @param parent 父节点
*/
public void down(int parent)
{
while (true)
{
int left = parent * 2 + 1;
int right = left + 1;
if (isMaxHeap) //大顶堆
{
int max = parent;
if (left < size && arr[left] > arr[max])
{
max = left;
}
if (right < size && arr[right] > arr[max])
{
max = right;
}
if (max != parent)
{
swap(parent,max);
parent = max;
}
else
{
break;
}
}
else//小顶堆
{
int min = parent;
if (left < size && arr[left] < arr[min])
{
min = left;
}
if (right < size && arr[right] < arr[min])
{
min = right;
}
if (min != parent)
{
swap(parent,min);
parent = min;
}
else
{
break;
}
}
}
}
/**
* 交换数组中两个元素
* @param i 索引i
* @param j 索引j
*/
public void swap(final int i,final int j)
{
int t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
/**
* 判断堆是否为空
* @return 如果堆为空,返回true
*/
public boolean isEmpty()
{
return size == 0;
}
/**
* 判断堆是否已满
* @return 如果堆已满,返回true
*/
public boolean isFull()
{
return size == arr.length;
}
@Override
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append("[");
for (int i = 0; i < size; i ++)
{
sb.append(arr[i]);
if (i != size - 1)
{
sb.append(",");
}
}
sb.append("]");
return sb.toString();
}
}
这里的get和set方法我用lombok去构建了,isMaxHeap变量用于标识要创建大顶堆还是小顶堆,默认是个大顶堆。