优先队列

       优先队列是一种特殊的队列,只是弹出元素时弹出的是(权重或者某个指定key)最大的元素。基于有序数组、无序数组、有序链表的实现类似于栈和队列的算法,这里说说基于完全二叉树的最大堆实现。

       完全二叉树的层次遍历序列和数组的索引顺序完全一致,这里用数组来存储二叉树的节点值,数组索引之间的关系可以表示树节点的父子关系:某节点在数组中索引为k,其父节点索引为k/2,左右子节点为2k和2k+1(k>=1)。最大堆要求:所有父节点的值大于等于子节点。的数组大小和堆的规模两者需要协调,在插入和弹出元素时,我们需要维护这个数组和堆的大小,数据结构如下:

public class HeapMaxPQ<Key extends Comparable<Key>> {
        public static final int DEFAULT_SIZE=16;
	
	public Key[] pq;
	public int size;
}

       在向堆里面插入元素,先将元素放在堆数组元素序列尾部(二叉树的最底部最右边的空位),再进行上浮操作。弹出(最大)元素时,堆顶就是最大元素,将堆顶元素和堆尾元素置换,此时堆顶元素进行下沉操作,堆尾元素清空弹出,堆规模减一。上浮和下称操作在插入和弹出操作中最为基础,而且让插入和弹出操作变得简单容易实现。

代码如下:

        private void swim(int i)
	{
		while(i/2>=1)
		{
			if(!less(i,i/2))
				exchange(i,i/2);
			else
				break;
			i/=2;
		}
	}
	private void sink(int i)
	{
		while(2*i<=this.size)
		{
			int j=2*i;
			if(j<this.size && less(j,j+1)) j++;//索引为i的值与其子节点中较大的进行比较
			if(!less(j,i))
				exchange(i,j);
			else
				break;
			i*=2;
		}
	}

有了上浮和下称操作,插入和弹出操作就很简单了:

        public void insert(Key k) {
		if(this.pq.length-1==this.size)
			this.resize(this.pq.length*2);//调整数组大小以适应堆的大小
		this.pq[++this.size]=k;
		swim(this.size);
	}
        public Key delMax() {
 		Key max=this.pq[1];
		this.pq[1]=this.pq[this.size];
		this.pq[this.size]=null;
		this.size--;
		sink(1);
		return max;
	}

上面的几个操作中涉及到数组大小的调整和比较交换等基本操作,代码如下:

        public HeapMaxPQ(){
		this(DEFAULT_SIZE);
	}
	
	@SuppressWarnings("unchecked")
	public HeapMaxPQ(int max){
		this.pq=(Key[]) new Comparable[max+1];//有效索引为1-max
		this.size=0;
	}
	
	public HeapMaxPQ(Key[] keys){
		for(int i=0;i<keys.length;i++)
			this.insert(keys[i]);
	}
	
	@SuppressWarnings("unchecked")
	private void resize(int new_capacity)
	{
		if(new_capacity>this.pq.length)
		{
			Key[] tmp=(Key[]) new Comparable[new_capacity];
			for(int i=1;i<this.pq.length;i++)
				tmp[i]=this.pq[i];
			this.pq=tmp;
		}
	}

        private boolean less(int a,int b)
	{
		if(this.pq[a].compareTo(this.pq[b])<=0)
			return true;
		else
			return false;
	}
	
	private void exchange(int i,int j)
	{
		Key tmp=this.pq[i];
		this.pq[i]=this.pq[j];
		this.pq[j]=tmp;
        }
上述算法思想借鉴学习了Princeton第四版《Algorithms》。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值