优先队列PriorityQueue

leetcode刷题是遇到一道按照二进制1的个数排列数组元素的题;

* 给你一个整数数组 arr 。请你将数组中的元素按照其二进制表示中数字 1 的数目升序排序。
* 如果存在多个数字二进制中 1 的数目相同,则必须将它们按照数值大小升序排列。
* 请你返回排序后的数组。

一般我们都是通过函数  num &= num - 1来计算二进制中1的个数,这个肯定是可以的

public int countBit1(int num) {
    int count = 0;
    while (num != 0) {
        num &= num - 1;  //去掉一个低位1
        count++;
    }
    return count;
}

但是我做完,再看其他人的解法时,发现有个使用优先队列来存储和排序数组的方法,觉得也十分巧妙

PriorityQueue<Integer> pQ = new PriorityQueue<>(new Comparator<Integer>() {
    @Override
    public int compare(Integer o1, Integer o2) {
        if (Integer.bitCount(o1) == Integer.bitCount(o2)) {
            return o2 - o1;
        }
        return Integer.bitCount(o1) - Integer.bitCount(o2);
    }
});

该方法主要使用Integer自带的bitCount方法,来计算1的个数,通过重写Comparator方法,来自定义PriorityQueue的排序原则

对此我对优先队列的源码进行的一些研究

1,优先队列的数据结构

public class PriorityQueue<E> extends AbstractQueue<E>
    implements java.io.Serializable {
    transient Object[] queue;    //队列容器, 默认是11
    private int size = 0;  //队列长度
    private final Comparator<? super E> comparator;  //队列比较器, 为null使用自然排序
    //....
}

和常规的队列相比多了一个Comparator方法,通过重写这个方法来自定义排序规则

 

2,优先队列是线程安全的吗?

我们来看入队的offer方法

 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;
    }

可以看出PriorityQueue并不是线程安全队列,因为offer都没有对队列进行锁定,如果要拥有线程安全的优先级队列,需要额外进行加锁操作 

 

3,如何进行排序的?

两种方式,指定比较器和使用默认比较器

  private void siftUp(int k, E x) {
        if (comparator != null)
            siftUpUsingComparator(k, x);   //指定比较器
        else
            siftUpComparable(k, x);   //没有指定比较器,使用默认的自然比较器
    }

这里主要关注自定义比较器,使用选择排序法将入列的元素放左边或者右边.
从源码上看PriorityQueue的入列操作并没对所有加入的元素进行优先级排序。仅仅保证数组第一个元素是最小的即可。

  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;
    }

 所以当我们每次通过poll方法放回第一个元素时,我们就可以获得最小的元素(假设升序排列),依次类推,当所有元素出队列   时,就可以做到全局有序

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值