优先级队列java代码模拟实现

一、前情提要

        Java 集合框架中提供了 PriorityQueue PriorityBlockingQueue 两种类型的优先级队列, PriorityQueue 是线 程不安全的, PriorityBlockingQueue 是线程安全的 ,本文主要介绍的是对于 PriorityQueue的代码模拟实现 。(ps:为了方便大家理解,这里我推荐一个算法动画视频,对于理解下面代码很有帮助,下面代码也是算是对于动画的实践或补充吧。点这->算法动画视频

二、具体代码实现

(1)定义优先级队列,包括成员变量和构造方法:

public class PriorityQueue {
    private int[] elem; // 存储堆元素的数组
    private int usedSize; // 记录当前堆中元素个数
    private static final int DEFAULT_CAPACITY = 10; // 默认初始容量

    public PriorityQueue() {
        this.elem = new int[DEFAULT_CAPACITY];
        this.usedSize = 0;
    }

(2)建堆

/**
     * 建堆:从最后一个非叶子节点开始向下调整
     * 时间复杂度:O(n)
     * @param array 传入的无序数组
     */
    public void createHeap(int[] array) {
        if (array == null || array.length == 0) return;
        this.elem = new int[array.length];
        System.arraycopy(array, 0, this.elem, 0, array.length);
        this.usedSize = array.length;
        for (int i = (usedSize - 2) / 2; i >= 0; i--) {
            shiftDown(i, usedSize);
        }
    }

(3)向下调整

/**
     * 向下调整(维持堆的性质)
     * 时间复杂度:O(log n)
     */
    private void shiftDown(int root, int len) {
        int parent = root;
        int child = 2 * parent + 1; // 左孩子
        while (child < len) {
            // 选择较大的子节点
            if (child + 1 < len && elem[child + 1] > elem[child]) {
                child++;
            }
            if (elem[parent] >= elem[child]) {
                break;
            }
            swap(parent, child);
            parent = child;
            child = 2 * parent + 1;
        }
    }

(4)插入元素

/**
     * 插入元素
     * 先插入到数组末尾,然后向上调整
     */
    public void push(int val) {
        if (isFull()) {
            resize();
        }
        elem[usedSize] = val;
        shiftUp(usedSize);
        usedSize++;
    }

(5)向上调整

/**
     * 向上调整(插入后保证堆的性质)
     * 时间复杂度:O(log n)
     */
    private void shiftUp(int child) {
        int parent = (child - 1) / 2;
        while (child > 0 && elem[child] > elem[parent]) {
            swap(child, parent);
            child = parent;
            parent = (child - 1) / 2;
        }
    }

(6)取出堆顶元素

/**
     * 取出堆顶元素(删除最大元素)
     * 用最后一个元素替换堆顶,然后向下调整
     */
    public void pollHeap() {
        if (isEmpty()) {
            throw new RuntimeException("Priority Queue is empty");
        }
        swap(0, usedSize - 1);
        usedSize--;
        shiftDown(0, usedSize);
    }

(7)获取堆顶元素

/**
     * 获取堆顶元素(最大值)
     */
    public int peekHeap() {
        if (isEmpty()) {
            throw new RuntimeException("Priority Queue is empty");
        }
        return elem[0];
    }

(8)空满合法性判断

 /**
     * 判断堆是否已满
     */
    public boolean isFull() {
        return usedSize == elem.length;
    }

    /**
     * 判断堆是否为空
     */
    public boolean isEmpty() {
        return usedSize == 0;
    }

(9)数组扩容

 /**
     * 数组扩容(动态扩展)
     */
    private void resize() {
        int newCapacity = elem.length * 2;
        int[] newArray = new int[newCapacity];
        System.arraycopy(elem, 0, newArray, 0, elem.length);
        elem = newArray;
    }

(10)交换数组两个元素

/**
     * 交换数组中两个元素
     */
    private void swap(int i, int j) {
        int temp = elem[i];
        elem[i] = elem[j];
        elem[j] = temp;
    }

三、补充

上述代码中,我都在注释中写明了时间复杂度,其中有一个可能大家很难理解,那就是建堆的复杂度,我这边给大家手写推一下,以下为推导过程:

       因为堆是完全二叉树,而满二叉树也是完全二叉树,此处为了简化使用满二叉树来证明 ( 时间复杂度本来看的就是近似值,多几个节点不影响最终结果)
因此建堆的时间复杂度为O(n)。
感谢你能看到这,希望对你有所帮助,可以的话点个赞吧,感恩~

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值