数据结构实现之最小优先队列(最小堆)

package xwq.dt;

import java.util.Comparator;
import java.util.Iterator;
import java.util.NoSuchElementException;

import xwq.util.StdIn;
import xwq.util.StdOut;

/**
 ***************************************************************** 
            **************** 最小优先队列API ****************
    1、构造函数
    public MinPQ();
    public MinPQ(int capacity);
    public MinPQ(Comparator cmp);
    public MinPQ(int capacity,Comparator cmp);
    public MinPQ(Key[] keys);
    public MinPQ(Key[] keys,Comparator);

    2、队列操作
    public boolean isEmpty();
    public int size();
    public void push(Key key); 动态扩容*2
    public Key pop();
    public Key peek();
    private void resize(int capacity);

    3、堆辅助操作
    private void adjustDown(int index);
    private void adjustUp(int index);
    private boolean less(Key k1,Key k2);
    private void swap(Key[] keys,int i,int j);

 ******************************************************************
 */
public class MinPQ<Key extends Comparable<Key>> implements Iterable<Key > {
    private Key[] pq;
    private int N;
    private Comparator comparator;

    //默认构造函数
    public MinPQ() {
        this(1);
    }

    //初始化空的最小优先队列,给定初始容量
    public MinPQ(int capacity) {
        this(capacity,null);
    }

    //初始化具有比较器的最小优先队列
    public MinPQ(Comparator cmp) {
        this(1,null);
    }

    //初始化具有比较器和初始容量的最小优先队列
    public MinPQ(int capacity,Comparator cmp) {
        pq = (Key[])new Comparable[capacity+1];
        N = 0;
        comparator = cmp;
    }

    //初始化给定数组的最小优先队列
    public MinPQ(Key[] keys) {
        this(keys,null);
    }

    //初始化给定数组以及比较器的最小优先队列
    public MinPQ(Key[] keys,Comparator cmp) {
        this(keys.length,cmp);
        N = keys.length;
        for(int i=0;i<keys.length;i++) 
            pq[i] = keys[i];
        for(int i=N/2;i>=1;i--)
            adjustDown(i);
    }

    /**
     * 判断最小优先队列是否为空
     * @return
     */
    public boolean isEmpty() {
        return N == 0;
    }

    /**
     * 获取目前最小优先队列中所存储元素的个数
     * @return
     */
    public int size() {
        return N;
    }

    /**
     * 入队,插入元素到最小优先队列
     * @param key
     */
    public void push(Key key) {
        //如果当前队列容量已满,扩充队列
        if(N == pq.length-1)
            resize(2*N);
        pq[++N] = key;
        adjustUp(N);
    }

    /**
     * 出队,删除最小优先队列的队头元素
     * @return
     */
    public Key pop() {
        if(isEmpty())
            throw new NoSuchElementException("MinPQ has empty.");
        Key min = pq[1];
        swap(1,N--);
        adjustDown(1);
        pq[N+1] = null;//防止被删除位置元素指针不稳定,以便垃圾收集的执行
        //如果队列容量为所存储元素个数的四倍,缩小队列使用容量
        if( N == (pq.length-1)/4 )
            resize((pq.length-1)/2);
        return min;
    }

    /**
     * 获取最小优先队列的队头元素
     * @return
     */
    public Key peek() {
        if(isEmpty())
            throw new NoSuchElementException("MinPQ has empty.");
        return pq[1];
    }

    /**
     * 返回MinPQ的迭代器
     */
    @Override
    public Iterator<Key> iterator() {
        return new HeapIterator();
    }

    /**
     * 重新定义队列容量
     * @param capacity
     */
    private void resize(int capacity) {
        assert N < capacity;
        Key[] news = (Key[])new Comparable[capacity+1];
        for(int i = 1 ;i <= N ;i++)
            news[i] = pq[i];
        pq = news;
    }

    /**
     * 向下调整堆
     * @param index
     */
    private void adjustDown(int index) {
        while(2*index<=N) {
            int l = 2*index;//index的左孩子
            //如果有右孩子,且右孩子小于左孩子,选择右孩子
            if(l<N && greater(l,l+1))
                l++;
            //比较index与孩子的大小
            //如果index比孩子小,则已满足最小堆性质,结束
            if(greater(l,index))
                break;
            //否则交换index与孩子的值,继续向下迭代
            swap(l,index);
            index = l;
        }
    }

    /**
     * 向上调整堆
     * @param index
     */
    private void adjustUp(int index) {
        while(index>1) {
            int p = index/2;
            //index比父母值大,满足最小堆性质,结束
            if(greater(index,p))
                break;
            //否则交换index与其父母的值,继续向上迭代
            swap(index,p);
            index = p;
        }
    }

    /**
     * 判断队列中的pq[i],pq[j]的大小
     * @param i pq[i]
     * @param j pq[j]
     * @return pq[i]>pq[j] 返回true
     */
    private boolean greater(int i,int j) {
        if(comparator != null)
            return comparator.compare(pq[i], pq[j]) > 0;
        else
            return ((Comparable)pq[i]).compareTo(pq[j]) > 0;
    }   

    /**
     * 交换队列中的pq[i],pq[j]元素值
     * @param i pq[i]
     * @param j pq[j]
     */
    private void swap(int i,int j) {
        Key t = pq[i]; pq[i] = pq[j]; pq[j] = t;
    }


    /**
     * MinPQ的迭代器,因为操作关系所以不支持删除操作
     */

    private class HeapIterator implements Iterator<Key> {
        //创建一个新的最小优先队列
        private MinPQ<Key> copy;

        // copy堆中的所有元素
        // 由于原顺序已满足堆性质,所以只需花费线性时间
        public HeapIterator() {
            if(comparator == null) 
                copy = new MinPQ(N);
            else
                copy = new MinPQ(N,comparator);
            for(int i=1;i<=N;i++)
                copy.push(pq[i]);
        }

        @Override
        public boolean hasNext() {
            return copy.size() > 0;
        }
        @Override
        public Key next() {
            if(copy.size() <=0 )
                throw new NoSuchElementException("MinPQ has empty.");
            return copy.pop();
        }
        @Override
        public void remove() {
            throw new UnsupportedOperationException("iterator do not support remove operation.");
        }
    }

    public static void main(String[] args) {
        MinPQ<String > pq = new MinPQ<String>();
        while(!StdIn.isEmpty()) {
            String s = StdIn.readString();
            if(!s.equals("-"))
                pq.push(s);
            else if(!pq.isEmpty())
                StdOut.print(pq.pop()+" ");
        }
        StdOut.println("size:"+pq.size());
        for(String s:pq)
            StdOut.print(s+" ");
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值