自定义代码实现最大优先队列与最小优先队列

最大优先队列

实际上就使基于最大堆实现的,取出元素时取出堆中最大的元素即可,并非先进先出

public class MaxPriorityQueue<T extends Comparable<T>> {

    //存储元素的数组
    private T[] items;
    //记录堆中元素的个数
    private int N;

    //优先队列构造方法
    public MaxPriorityQueue(int capacity){
        this.items= (T[]) new Comparable[capacity+1];
        this.N=0;
    }

    /**
     * 返回优先队列中存储的元素个数
     * @return
     */
    public int size(){return N;}

    /**
     * 优先队列是否为空
     * @return true 空 false 不为空
     */
    public boolean isEmpty(){return N==0;}

    /**
     * i索引处的值是否小于j索引处的值
     * @param i
     * @param j
     * @return true 小于 false 大于
     */
    private boolean less(int i,int j){
        return items[i].compareTo(items[j])<0;
    }

    /**
     * 交换索引i与索引j处的元素
     * @param i
     * @param j
     */
    private void exchange(int i,int j){
        T temp=items[i];
        items[i]=items[j];
        items[j]=temp;
    }

    /**
     * 往堆中插入一个元素
     * @param t
     */
    public void insert(T t){
        if (isEmpty()){
            //队列中无存储元素,新增元素为根结点元素
            items[1]=t;
            //元素个数+1
            N++;
            return;
        }
        //队列中已存储元素,将新元素存储到数组的最后一个元素的后一位
        items[N+1]=t;
        //元素个数+1
        N++;
        //利用上浮算法将新增的元素置于堆结构的正确位置
        swim(N);
    }

    /**
     * 上浮算法,将所有k处的元素调整到堆中正确的位置,保持堆的结构
     * @param k
     */
    private void swim(int k){
        while (k/2>=1){
            //当前结点有父结点,与父结点比较大小
            if (less(k,k/2)){
                //当前结点小于父结点的值,那么该位置就为正确位置直接结束循环
                break;
            }
            //当前结点的值大于父结点的值,则交换二者元素
            exchange(k,k/2);
            //交换元素后继续循环比较与新结点位置父结点的值大小
            k=k/2;
        }
    }


    /**
     * 删除最大优先队列中的最大元素(即堆中根结点的元素)并返回
     * @return
     */
    public T delMax(){
        //交换索引1与索引N处的元素
        exchange(1,N);
        //创建临时根结点
        T temp=items[N];
        //删除最后最大元素
        items[N]=null;
        //元素个数-1
        N--;
        //让临时根结点的元素下沉到正确位置
        sink(1);
        //返回最大元素
        return temp;
    }


    /**
     * 下沉算法,使索引k位置的元素下沉到正确的位置
     * @param k
     */
    private void sink(int k){
       if (isEmpty()){
           //堆为空 无需下沉
           return;
       }
       //堆不为空
        while (2*k<=N){
            //当前结点存在左子结点
            int max;//记录左右子结点中较大者的索引
            if(2*k+1<=N){
                //存在右子结点
                if(less(2*k,2*k+1)){
                    //左子结点的元素小于右子结点的元素
                    max=2*k+1;
                }else {
                    //左子结点的元素大于右子结点的元素
                    max=2*k;
                }
            }else {
                //右子结点不存在
                max=2*k;
            }
            //比较当前结点与max索引的大小
            if(!less(k,max)){
                //当前结点比max索引的值大,正确该元素已经下沉到正确的位置,直接结束循环
                break;
            }
            //当前结点比max索引的值小,交换元素继续下沉寻找正确位置
            exchange(k,max);
            k=max;
        }
        //循环结束条件
        // 1.无左子结点,已经沉到低(该位置为正确位置)
        //2.找到了正确位置提前结束了循环
    }
}
最小优先队列

实际上是基于最小堆实现的,取出元素时取出堆中最小的元素即可

public class MinPriorityQueue<T extends Comparable<T>> {

    //存储元素的数组
    private T[] items;
    //记录堆中元素的个数
    private int N;

    //优先队列构造方法
    public MinPriorityQueue(int capacity){
        this.items= (T[]) new Comparable[capacity+1];
        this.N=0;
    }

    /**
     * 返回优先队列中存储的元素个数
     * @return
     */
    public int size(){return N;}

    /**
     * 优先队列是否为空
     * @return true 空 false 不为空
     */
    public boolean isEmpty(){return N==0;}

    /**
     * i索引处的值是否小于j索引处的值
     * @param i
     * @param j
     * @return true 小于 false 大于
     */
    private boolean less(int i,int j){
        return items[i].compareTo(items[j])<0;
    }

    /**
     * 交换索引i与索引j处的元素
     * @param i
     * @param j
     */
    private void exchange(int i,int j){
        T temp=items[i];
        items[i]=items[j];
        items[j]=temp;
    }

    /**
     * 往堆中插入一个元素
     * @param t
     */
    public void insert(T t){
        if (isEmpty()){
            //队列中无存储元素,新增元素为根结点元素
            items[1]=t;
            //元素个数+1
            N++;
            return;
        }
        //队列中已存储元素,将新元素存储到数组的最后一个元素的后一位
        items[N+1]=t;
        //元素个数+1
        N++;
        //利用上浮算法将新增的元素置于堆结构的正确位置
        swim(N);
    }

    /**
     * 上浮算法,将所有k处的元素调整到堆中正确的位置,保持堆的结构
     * @param k
     */
    private void swim(int k){
      while (k/2>=1){
          //当前结点右父结点
          if(!less(k,k/2)){
              //当前结点大于父结点,则已经上浮到了正确位置直接结束循环
              break;
          }
          //当前结点小于父结点,交换元素 继续上浮
          exchange(k,k/2);
          k=k/2;
      }
    }


    /**
     * 删除最小优先队列中的最小元素(即堆中根结点的元素)并返回
     * @return
     */
    public T delMin(){
        //交换索引1与索引N处的元素
        exchange(1,N);
        //创建临时根结点
        T temp=items[N];
        //删除最后最小元素
        items[N]=null;
        //元素个数-1
        N--;
        //让临时根结点的元素下沉到正确位置
        sink(1);
        //返回最大元素
        return temp;
    }


    /**
     * 下沉算法,使索引k位置的元素下沉到正确的位置
     * @param k
     */
    private void sink(int k){
       if (isEmpty()){
           //堆为空 无需下沉
           return;
       }
       //堆不为空
        while (2*k<=N){
           //当前结点存在左子结点进行下沉
            int min;//记录当前子结点的左右子结点中值较小的索引
            if (2*k+1<=N){
                //当前子结点存在左右子结点
                if (less(2*k,2*k+1)){
                    //左子结点的值小于右子结点的值
                    min=2*k;
                }else {
                    //左子结点的值大于右子结点的值
                    min=2*k+1;
                }
            }else {
                //右子结点不存在
                min=2*k;
            }

            //比较当前结点与min
            if (less(k,min)){
                //当前结点小于min。已经下沉到了正确的位置 停止循环
                break;
            }
            //当前结点大于min 交换元素继续下沉寻找正确位置
            exchange(k,min);
            k=min;
        }
        //循环结束条件
        // 1.无左子结点,已经沉到低(该位置为正确位置)
        //2.找到了正确位置提前结束了循环
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值