数据结构和算法(树)- 优先队列

优先队列特点

  1. 队列是FIFO(先进先出)
  2. 优先队列:
    • 最大优先队列,不管入队顺序怎么样,都是当前最大的元素优先出队
    • 最小优先队列,不管入队顺序怎么样,都是当前最小的元素优先出队

实现方法

  1. 利用二叉堆的特点
    • 最大堆的堆顶就是最大元素
    • 最小堆的堆顶就是最小元素
  2. 入队:放到数组末尾,然后上浮这个节点到合适的位置
  3. 出队:删除堆顶元素,最后一个补充到堆顶,堆顶元素下沉
  4. 思考:上浮和下沉的时间复杂度都是O(logn),因此入队和出队的时间复杂度也是O(logn)

代码实现(最大堆为例)

public class PriorityQueue {

    private int[] array;//存放元素的
    private int size;//数组中,元素的实际个数

    public PriorityQueue(){
        //队列初始长度32
        array = new int[32];
    }

    /**
     * 入队
     * @param key  入队元素
     */
    public void enQueue(int key) {
        //如果队列元素数量超出范围,扩容
        if(size >= array.length){
            resize();
        }
        //添加元素到末尾,然后进行上浮调整,找到合适的位置
        array[size++] = key;
        upAdjust();
    }

    /**
     * 出队
     */
    public int deQueue() throws Exception {
        //队列中没有元素,出队会抛出异常
        if(size <= 0){
            throw new Exception("the queue is empty !");
        }
        //获取堆顶元素,出队
        int head = array[0];
        //最后一个元素移动到堆顶,然后下沉
        array[0] = array[--size];
        downAdjust();
        return head;
    }

    /**
     * 上浮调整,最后一个元素上浮
     */
    private void upAdjust() {
        int childIndex = size-1;
        int parentIndex = (childIndex-1)/2;
        // temp保存插入的叶子节点值,用于最后的赋值
        int temp = array[childIndex];
        // 比父节点大,就上浮
        while (childIndex > 0 && temp > array[parentIndex])
        {
            //无需真正交换,单向赋值即可
            array[childIndex] = array[parentIndex];
            childIndex = parentIndex;
            parentIndex = (parentIndex-1) / 2;
        }
        array[childIndex] = temp;
    }

    /**
     * 下沉调整
     */
    private void downAdjust() {
        // temp保存父节点值,用于最后的赋值
        int parentIndex = 0;
        int temp = array[parentIndex];
        int childIndex = 1;
        while (childIndex < size) {
            // 如果有右孩子,且右孩子大于左孩子的值,则定位到右孩子。找左右孩子中最大的那个
            if (childIndex + 1 < size && array[childIndex + 1] > array[childIndex]) {
                childIndex++;
            }
            // 如果父节点大于最大的孩子,直接跳出,已经找到合适的位置了
            if (temp >= array[childIndex])
                break;
            // 父节点小于最大的那个孩子,父节点要下沉
            // 无需真正交换,单向赋值即可
            array[parentIndex] = array[childIndex];
            parentIndex = childIndex;
            childIndex = 2 * childIndex + 1;
        }
        array[parentIndex] = temp;
    }

    /**
     * 队列扩容
     */
    private void resize() {
        //队列容量乘以2
        int newSize = this.size * 2;
        this.array = Arrays.copyOf(this.array, newSize);
    }

    public static void main(String[] args) throws Exception {
        PriorityQueue priorityQueue = new PriorityQueue();
        priorityQueue.enQueue(3);
        priorityQueue.enQueue(6);
        priorityQueue.enQueue(1);
        priorityQueue.enQueue(5);
        priorityQueue.enQueue(2);
        System.out.println("出队元素:" + priorityQueue.deQueue());
        System.out.println("出队元素:" + priorityQueue.deQueue());
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值