数据结构之-优先队列PriorityQueue实现

队列是一个先进先出的结构,可以用链表呀,数组来实现它,我们今天用数组实现个队列,以优先级队列方式,我们看看怎么实现,优先级队列以队列存储时规则会将即将过期的或较小的数据存储在前面,这样取出时则取头部数据即可。

优先级队列采用数组实现的完全二叉树,根据二叉树规则,在插入的时候对比,保证父节点要比子节点小就ok。

我们主要来看下入队出队的一个实现,需要定义接口,咱们来定义基本方法。

1.实现入队用add或offer,这里超出队列界限抛出异常什么的都不处理,这里add会调用offer方法

2.出队使用poll方法则是移除队列头部并返回队列头部数据,使用peek方法只得到头部数据不处理移除头部数据。

/**
 * @Author df
 * @Date 2022/11/28 16:48
 * @Version 1.0
 * java泛型中标记符含义
 * E element  (元素,集合中使用)
 * T type  (java类)
 * K key   (键)
 * V value (值)
 * N number(数值)
 * ? 表示不确定的java类型
 */
public interface Queue<E> {
    // 入队,超出队列界限抛出异常处理
    boolean add(E e);

    // 入队,超出队列界限直接返回false
    boolean offer(E e);

    // 将首个队列元素弹出,如果空为空
    E poll();
    // 查询首个队列,不移除首个队列,如果队列为空抛出异常
    E peek();
}

定义实现方法 PriorityQueue,准备一下,我们需要一个数组,这个数组我们就叫queue吧,还需要一个默认的容量就叫DEFAULT_INITIAL_CAPACITY=11,还需要个长度元素,记录数组长度,就叫size把,在实例化时,就会开辟默认数组空间

public class PriorityQueue<E> implements Queue<E> {    
    private static final int DEFAULT_INITIAL_CAPACITY = 11;
    // 用数组实现队列
    transient Object[] queue;
    private int size = 0;

    // 默认
    public PriorityQueue() {
        queue = new Object[DEFAULT_INITIAL_CAPACITY];
    }
}

准备工作做好就需要入队列了

1.入队

入队前我们先想想,我们怎么存储才能按顺序二叉树规则存储?

那么假如我存储一个3,假如在数组queue[0]直接插入3,我再存储个2,我直接在数组queue[1]存储2呢,我在插入个数据1,直接在queue[2]插入1,那么就形成了这样的二叉树  

                                                 3

                                          2            1

但是这不符合二叉树的规则,父节点要比任意子节点要小,现在父节点是3,它比其他子节点都要大,所以这样不对。我们要考虑在添加的时候需要对比,然后存储对应的位置就好了

如第一个元素3直接存储,第二个元素存储时则找到父节点值进行比对,3比2大则替换,将queue[0]变为2,queue[1]变为3,再存储1时则跟父节点queue[0]对比,1小于2则替换,

                                               1

                                       3            2

再新添加元素还是一样的方式,如果此时存储进来5对比以后比前3个位置都大,那么就存储queue[3],6就存储queue[4]而queue[1]就是它的父节点

                                              1

                                      3              2

                                  5      6     

你此时可能在想5和6是3的子节点,如果数据渐渐变大,怎么依次找他们自己的父节点呢,这就引申出来一个公式

父节点=  (n-1)/2     5的坐标为3,(3-1)/2=1  queue[1]就是queue[3]的父亲节点

添加操作,add()调用offer(),offer方法用来判断是否超出当前队列容量进行扩容调用grow(),以及调用siftUp()用来处理子父节点判断并替换操作。

offer():先判断是否扩容,默认进来size为0,queue队列长度是11个空值,所以是不用扩容,因为要往队列存储值了,所以设置size为i+1,然后判断是不是第一次存储值,第一次存储值就直接在queue[0]直接存储,如不是,则需要进入siftUp();

siftUp():参数传当前待插入的位置i,当前元素e,进入siftUpComparable();

siftUpComparable():先把当前的元素转换为Comparable,这样就可以进行值的比对,我们最重要的点就是通过当前元素位置找到父节点位置的值,然后进行比对,子节点小于父节点,就需要替换元素。

需用到公式找父节点,(k-1)/2 ,k>0  ,假如现在k为1,那就是(1-1)/2=0,先存储3,再存储2,那么2的父节点就是3,取出父节点的值进行比对,发现当前元素大于父节点,不退出循环,直接替换queue[k=1]=3,k=0,此时while条件无法满足,执行queue[k=0]=2,这样就可以保证父节点最小

    @Override
    public boolean add(E e) {
        r
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值