一、最大堆
二叉堆其实是一个完全二叉树,且每个节点的值总是小于其父节点。这种堆叫做最大堆。
用数组实现最大堆时,可以将根节点的角标设置成0,则每个节点i的父节点和左孩子,右孩子的角标关系如下:
parent(i)=(i-1)/2;
leftChild(i)=2i+1;
rightChild(i)2i+2;
基于数组实现的最大堆 MaxHeap:
public class MaxHeap<E extends Comparable<E>> {
private ArrayList<E> data; //写好的线性表
MaxHeap(){//构造函数内维护一个线性表
data=new ArrayList<>();
}
public MaxHeap(int capacity){
data=new ArrayList<>(capacity);
}
public MaxHeap(E[] arr){
data=new ArrayList<>(arr);
for(int i=parent(data.getSize()-1);i>=0;i--){
moveDown(i);
}
}
//返回堆中的元素个数
public int size(){
return data.getSize();
}
//判断是否为空
public boolean isEmpty(){
return data.isEmpty();
}
//以下为三个辅助函数;用于获取当前节点的左右孩子 和父节点
private int parent(int index){
if(index==0){
throw new IllegalArgumentException("没有父节点!");
}
return (index-1)/2;
}
private int leftChild(int index){
return 2*index+1;
}
private int rightChild(int index){
return 2*index+2;
}
//增加元素
public void add(E e){
data.addLast(e);//先插到最后,再与父节点相比较,上浮;
moveUp(data.getSize()-1);//将最后一个元素上浮
}
//元素上浮操作
private void moveUp(int index){
//如果父节点小于当前节点,就交换位置;
//直到父节点大于或等于它,或者没有父节点了。
while(index>0 && data.get(parent(index)).compareTo(data.get(index))<0){
data.swap(index, parent(index));//满足条件,交换位置;
index=parent(index);//交换位置后角标也互换
}
}
//获取堆中的最大值:
public E getMax(){
if(data.isEmpty()){
throw new IllegalArgumentException("堆为空");
}
return data.getFirst();
}
//删除堆中最大值;
public E deleteMax(){
E e=getMax();
data.swap(0, data.getSize()-1);//将最大值和最后一个值交换
data.removeLast();//再将最后一个值删除
moveDown(0);//再将第一个值下沉
return e;
}
private void moveDown(int index) {
while(leftChild(index)<data.getSize()){ //当该节点有左孩子
int k=leftChild(index);
//该节点有右孩子,且右孩子大于左孩子:
if(k+1<data.getSize()&&data.get(k+1).compareTo(data.get(k))>0){
k=rightChild(index); //k为左右孩子中最大的那个角标
}
if(data.get(index).compareTo(data.get(k))<0){
data.swap(index,k);
}else{
break;
}
}
}
//替换最大值(将原来的最大值移除,用e替换)
public E replace(E e){
E res=getMax();
data.set(0, e);
moveDown(0);
return res;
}
}
二、优先队列:
普通队列:先进先出,后进后出
优先队列:出队顺序和入队顺序无关,和优先级相关,本质还是队列;
本质应用:任务管理器中:动态选择优先级最高的任务执行
游戏中:塔防优先攻击(距离,威胁,先后)
PriorityQueue基于最大堆实现的优先队列的定义:
package 堆和优先队列;
import 动态数组.queue;
//优先队列
public class priorityQueue<E extends Comparable<E>>implements queue {
private MaxHeap<E> heap;
public priorityQueue(){
heap=new MaxHeap<E>();
}
@Override
public int getSize() {
return heap.size();
}
@Override
public boolean isEmpty() {
return heap.isEmpty();
}
public void enqueue(E e) { //进队
heap.add(e);
}
@Override
public E dequeue() { //出队,删除最大值
return heap.deleteMax();
}
@Override
public E getFront() { //获取队头
return heap.getMax();
}
@Override
public E getRear() {
return null;
}
@Override
public void clear() { //清空队列
heap.clear();
}
@Override
public void enqueue(Object e) {
}
}
对比普通线性结构时间复杂度如下:
入队 出队(拿出最大元素)
普通线性结构: O(1) O(n)
顺序线性结构: O(n) O(1)
堆: O(logn) O(logn)