- 堆
- 基于数组实现的最大堆(没有实现接口)上浮、下沉函数
package org.yanan.堆和优先队列;
import org.yanan.data.ArrayList;
//基于数组实现的最大堆
public class MaxHeap<E extends Comparable<E>> {
//1.定义成员变量和构造函数
private ArrayList<E> data;
public MaxHeap(){
data=new ArrayList<>();
}
public MaxHeap(int capacity){//创建指定容量大小的最大堆
data=new ArrayList<>(capacity);
}
//2.将任意数组整理成最大堆:从最后一个非叶结点开始寻找
public MaxHeap(E[] arr){
data=new ArrayList<>(arr);
//从最后一个元素的父节点开始
for(int i=parent(data.getSize()-1);i>=0;i--){
siftDown(i);
}
}
//3.返回堆中元素的个数
public int size(){
return data.getSize();
}
//4.判断堆中是否为空
public boolean isEmpty(){
//return data.getSize()==0;
return data.isEmpty();
}
//5.提供三个辅助函数:一个索引的父节点的索引,左孩子的索引,右孩子的索引
private int parent(int index){//当前结点的角标
if(index==0){//根节点无父节点
throw new IllegalArgumentException("none parent");
}
return (index-1)/2;
}
private int leftChild(int index){//左孩子
return 2*index+1;
}
private int rightChild(int index){//右孩子
return 2*index+2;
}
//6.向堆中添加元素:默认添加在数组最后,即堆的最末尾,然后进行上浮操作
public void add(E e){
data.addLast(e);//默认将添加的元素放到数组的尾部
siftUp(data.getSize()-1);//然后进行上浮操作
}
//6.1:上浮操作
private void siftUp(int index) {//上浮,得到要上浮元素的下标
while(index>0&&data.get(parent(index)).compareTo(data.get(index))<0){
//如果是根则无父节点,上浮的前提是当前的值大于父节点值
data.swap(index, parent(index));
index=parent(index);
}
}
//7.查看堆中最大元素
public E findMax(){
if(data.isEmpty()){
throw new IllegalArgumentException("堆为空");
}
return data.getFirst();
}
//8.删除堆中最大元素:最大堆的最大值在堆顶,下标为0,和最后一个元素交换位置,直接删除最后一个元素,然后堆顶元素下沉
public E extractMax(){
E e=findMax();
data.swap(0, data.getSize()-1);
data.removeLast();
siftDown(0);
return e;
}
//8.1:下沉操作 ,主要是堆顶元素和左右孩子比较
private void siftDown(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);
}
//比较index和k的大小
if(data.get(index).compareTo(data.get(k))<0){
data.swap(index, k);
}else{
break;
}
}
}
//9.替换最大值,取出最大值,放入一个新元素
public E replace(E e){
E res=findMax();
data.set(0, e);
siftDown(0);
return res;
}
public void clear() {
data.clear();
}
}
- 优先队列
普通队列:先进先出,后进后出
优先队列:出队顺序和入队顺序无关,和优先级相关,本质还是队列
应用: 任务管理器中:动态选择优先级最高的任务执行
游戏中:塔防优先攻击(距离,威胁,先后)
优先队列的经典问题
在1000000000个元素中选出前100名?
在N个元素中选出前M个元素 排序?
nlogm 使用优先队列,维护当前看到的前m个元素,最小堆(大小是相对的)
- 基于最大堆实现的优先队列
package org.yanan.堆和优先队列;
import org.yanan.data.Queue;
public class PriorityQueue<E extends Comparable<E>> implements Queue<E>{
private MaxHeap<E> heap;
public PriorityQueue(){
heap=new MaxHeap<>();
}
@Override
public int getSize() {
return heap.size();
}
@Override
public boolean isEmpty() {
return heap.isEmpty();
}
@Override
public void enqueue(E e) {
heap.add(e);
}
@Override
public E dequeue() {
return heap.extractMax();
}
@Override
public E getFront() {
return heap.findMax();
}
@Override
public E getRear() {
return null;
}
@Override
public void clear() {
heap.clear();
}
}