堆和优先队列

一、最大堆
二叉堆其实是一个完全二叉树,且每个节点的值总是小于其父节点。这种堆叫做最大堆。
用数组实现最大堆时,可以将根节点的角标设置成0,则每个节点i的父节点和左孩子,右孩子的角标关系如下:
parent(i)=(i-1)/2;
leftChild(i)=2
i+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)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值