PriorityQueue 源码解析

本文详细介绍了Java中的PriorityQueue类,包括其内部实现原理、关键方法如add、remove、poll的操作流程及堆调整算法siftUp和siftDown的具体实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

PriorityQueue是Java util包里的具有“优先级”特征的队列,其接受类需要实现Compara接口。PriorityQueue可以当作小顶堆使用(不实现任何Comparable接口,将会按照自然排序(nature odering排序)。

public class PriorityQueue<E> extends AbstractQueue<E>
    implements java.io.Serializable {
    //序列化识别id
    private static final long serialVersionUID = -7720805057305804111L;
    //默认的容量是11
    private static final int DEFAULT_INITIAL_CAPACITY = 11;
    //数组实现
    transient Object[] queue;
    //大小
    private int size = 0;
    //比较器(默认为自然比较)
    private final Comparator<? super E> comparator;
    //
    transient int modCount = 0;
    //常用方法
    PriorityQueue();
    PriorityQueue(int initialCapacity);
    PriorityQueue(Comparator<? super E> comparator);
    PriorityQueue(int initialCapacity,Comparator<? super E> comparator);
    PriorityQueue(Collection<? extends E> c);
    grow(int minCapacity);
    //添加
    public boolean add(E e) {
        return offer(e);
    }
    //取堆顶
    public E peek() {
        return (size == 0) ? null : (E) queue[0];
    }
    //删除
    public boolean remove(Object o) {
        int i = indexOf(o);
        if (i == -1)
            return false;
        else {
            removeAt(i);
            return true;
        }
    }
    //contains,顺序查找
    public boolean contains(Object o) {
        return indexOf(o) != -1;
    }
    //poll
    poll();
}
解析:
1. grow函数用于增加容量(如果容量小于64就双倍容量,大于64就增加50%)
1. add(E e)
public boolean add(E e) {
        return offer(e);
    }

public boolean offer(E e) {
        if (e == null)
            throw new NullPointerException();
        modCount++;
        int i = size;
        if (i >= queue.length)
            grow(i + 1);
        size = i + 1;
        if (i == 0)
            queue[0] = e;
        else
            siftUp(i, e);
        return true;
    }

解析:
1. add函数调用了offer
2. offer函数首先检查了是否超过容量,如果超过容量就调用grow函数增加容量
3. 然后调用siftUp函数插入元素
4. 插入的主要逻辑就是 把整个Object数组当作是小顶堆(完全二叉树),具体逻辑看代码注释

2. remove(Object o)

删除元素同时为了保持整个小顶堆,需要做调整

public boolean remove(Object o) {
    int i = indexOf(o); //顺序查找o的位置
    if (i == -1)
        return false;
    else {
        removeAt(i);//调用具体函数
        return true;
    }
}

private E removeAt(int i) {
        // assert i >= 0 && i < size;
        modCount++;
        int s = --size;
        if (s == i) // removed last element
            queue[i] = null;
        else {
            E moved = (E) queue[s];//取出最后一个元素
            queue[s] = null;
            siftDown(i, moved);
            if (queue[i] == moved) {
                siftUp(i, moved);
                if (queue[i] != moved)
                    return moved;
            }
        }
        return null;
    }

1.删除元素时,首先查找元素的位置,调用removeAt删除元素
2.将最后一个元素取出,然后置空,调整小顶堆

    /**
     * Inserts item x at position k, maintaining heap invariant by
     * promoting x up the tree until it is greater than or equal to
     * its parent, or is the root.
     *
     * To simplify and speed up coercions and comparisons. the
     * Comparable and Comparator versions are separated into different
     * methods that are otherwise identical. (Similarly for siftDown.)
     *
     * @param k the position to fill
     * @param x the item to insert
    //在k处插入元素,并向上调整堆至小顶堆
    private void siftUp(int k, E x) {
            if (comparator != null)
                siftUpUsingComparator(k, x);
            else
                siftUpComparable(k, x);
        }

    @SuppressWarnings("unchecked")

    private void siftUpComparable(int k, E x) {
       Comparable<? super E> key = (Comparable<? super E>) x;
       while (k > 0) {
           int parent = (k - 1) >>> 1;//查看当前节点的父亲节点
           Object e = queue[parent];
           if (key.compareTo((E) e) >= 0) //如果大于等于当前节点,break
               break;
           queue[k] = e; //如果小于,将父亲节点移到当前位置
           k = parent;//继续查看父亲节点
       }
       queue[k] = key;
    }

    @SuppressWarnings("unchecked")
    //同上,区别是使用了用户自定义
    private void siftUpUsingComparator(int k, E x) {
       while (k > 0) {
           int parent = (k - 1) >>> 1;
           Object e = queue[parent];
           if (comparator.compare(x, (E) e) >= 0)
               break;
           queue[k] = e;
           k = parent;
       }
       queue[k] = x;
    }


    /**
     * Inserts item x at position k, maintaining heap invariant by
     * demoting x down the tree repeatedly until it is less than or
     * equal to its children or is a leaf.
     *
     * @param k the position to fill
     * @param x the item to insert
     */
     //在k处插入x,向下调整小顶堆
    private void siftDown(int k, E x) {
        if (comparator != null)
            siftDownUsingComparator(k, x);  //使用用户定义比较器
        else
            siftDownComparable(k, x);  //使用默认比较器
    }

    @SuppressWarnings("unchecked")
    private void siftDownComparable(int k, E x) {
        Comparable<? super E> key = (Comparable<? super E>)x;
        int half = size >>> 1;        // loop while a non-leaf   从非叶子节点开始,叶子节点只用向上调整就行
        while (k < half) {
            int child = (k << 1) + 1; // assume left child is least 
            Object c = queue[child]; //位置k的左孩子
            int right = child + 1;   
            if (right < size && ((Comparable<? super E>) c).compareTo((E) queue[right]) > 0)   //左孩子比右孩子大
                c = queue[child = right];  //位置k的右孩子
            if (key.compareTo((E) c) <= 0)
                break;//如果key小于孩子中比较小的那个
            queue[k] = c;  //交换到k较小的孩子中继续比较,一直到叶子节点
            k = child; 
        }
        queue[k] = key;
    }

    @SuppressWarnings("unchecked")
    private void siftDownUsingComparator(int k, E x) {
        int half = size >>> 1;
        while (k < half) {
            int child = (k << 1) + 1;
            Object c = queue[child];
            int right = child + 1;
            if (right < size &&
                comparator.compare((E) c, (E) queue[right]) > 0)
                c = queue[child = right];
            if (comparator.compare(x, (E) c) <= 0)
                break;
            queue[k] = c;
            k = child;
        }
        queue[k] = x;
    }
3. poll()

取出最小值,并向下调整小顶堆

 @SuppressWarnings("unchecked")
    public E poll() {
        if (size == 0)
            return null;
        int s = --size;
        modCount++;
        E result = (E) queue[0];
        E x = (E) queue[s];
        queue[s] = null;
        if (s != 0)
            siftDown(0, x);
        return result;
    }
资源下载链接为: https://pan.quark.cn/s/22ca96b7bd39 在 IT 领域,文档格式转换是常见需求,尤其在处理多种文件类型时。本文将聚焦于利用 Java 技术栈,尤其是 Apache POI 和 iTextPDF 库,实现 doc、xls(涵盖 Excel 2003 及 Excel 2007+)以及 txt、图片等格式文件向 PDF 的转换,并实现在线浏览功能。 先从 Apache POI 说起,它是一个强大的 Java 库,专注于处理 Microsoft Office 格式文件,比如 doc 和 xls。Apache POI 提供了 HSSF 和 XSSF 两个 API,其中 HSSF 用于读写老版本的 BIFF8 格式(Excel 97-2003),XSSF 则针对新的 XML 格式(Excel 2007+)。这两个 API 均具备读取和写入工作表、单元格、公式、样式等功能。读取 Excel 文件时,可通过创建 HSSFWorkbook 或 XSSFWorkbook 对象来打开相应格式的文件,进而遍历工作簿中的每个 Sheet,获取行和列数据。写入 Excel 文件时,创建新的 Workbook 对象,添加 Sheet、Row 和 Cell,即可构建新 Excel 文件。 再看 iTextPDF,它是一个用于生成和修改 PDF 文档的 Java 库,拥有丰富的 API。创建 PDF 文档时,借助 Document 对象,可定义页面尺寸、边距等属性来定制 PDF 外观。添加内容方面,可使用 Paragraph、List、Table 等元素将文本、列表和表格加入 PDF,图片可通过 Image 类加载插入。iTextPDF 支持多种字体和样式,可设置文本颜色、大小、样式等。此外,iTextPDF 的 TextRenderer 类能将 HTML、
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值