• PriorityQueue源码阅读


    最小堆:优先级权重越小 离顶点越近

    案例
    1. 实现一个top max n

      publish static int[] topN(int[] nums, int l){
          int[] result = new int[l];
          Comparator c = new Comparator(){
              public int comparable(int a, int b){
                  return a - b > 0; 
              }
          };
          PriorityQueue pq = new PriorityQueue(l, c);
          for(int n = 0; n < nums.length; n++){
              pq.add(nums[i]);
          }
          for(int n = 0; n < l; n++){
              result[n] = pq.peek();//拿出堆顶元素
          }
          return result;
      }
      public void main(String[] args){
          int[] nums = {10,5,69,2,14,55,63};
          
      }
    问题
    1. 添加时向上调整:元素最开始插入的时候是从队尾进入的,所以一直向上比较大小

    2. 移除时向下调整:删除时最开始是先将队尾置空,将队尾元素覆盖目标删除位置,然后向下和左右孩子比较

    todo
    1. 以集合/队列等方式初始化:调整树结构时从队尾开始向下调整

    属性及构造器
    public class PriorityQueue<E> extends AbstractQueue<E> implements java.io.Serializable {
        //表现为一个平衡二叉树:queue[n]为queue[2*n+1]和queue[2*(n+1)]的父节点
        transient Object[] queue;
        private int size = 0;
        //比较器:根据比较器排列元素在队列中的顺序
        private final Comparator<? super E> comparator;
        public PriorityQueue() { this(DEFAULT_INITIAL_CAPACITY, null);}
        public PriorityQueue(int initialCapacity) {this(initialCapacity, null);}
        public PriorityQueue(Comparator<? super E> comparator) {
            this(DEFAULT_INITIAL_CAPACITY, comparator);
        }
        public PriorityQueue(int initialCapacity, Comparator<? super E> comparator) {
            // Note: This restriction of at least one is not actually needed,
            // but continues for 1.5 compatibility
            if (initialCapacity < 1)
                throw new IllegalArgumentException();
            this.queue = new Object[initialCapacity];
            this.comparator = comparator;
        }
    }
    内部类Itr:迭代器
    private final class Itr implements Iterator<E> {
        private int cursor = 0;
        //没被访问过的元素 迭代过程中被落下的元素
        private ArrayDeque<E> forgetMeNot = null;
        //最近被访问后的元素索引
        private int lastRet = -1;
        public boolean hasNext() {
            return cursor < size ||  (forgetMeNot != null && !forgetMeNot.isEmpty());
        }
        public E next() {
            //被其他线程修改过 抛出异常
            if (expectedModCount != modCount)
                throw new ConcurrentModificationException();
            if (cursor < size)
                return (E) queue[lastRet = cursor++];
            if (forgetMeNot != null) {
                lastRet = -1;
                //取 没被访问的集合 的第一个元素
                lastRetElt = forgetMeNot.poll();
                if (lastRetElt != null)
                    return lastRetElt;
            }
            throw new NoSuchElementException();
        }
        public void remove() {
            if (expectedModCount != modCount)
                throw new ConcurrentModificationException();
            if (lastRet != -1) {
                E moved = PriorityQueue.this.removeAt(lastRet);
                lastRet = -1;
                if (moved == null)
                    cursor--;
                else {
                    if (forgetMeNot == null)
                        forgetMeNot = new ArrayDeque<>();
                    forgetMeNot.add(moved);
                }
            } else if (lastRetElt != null) {
                PriorityQueue.this.removeEq(lastRetElt);
                lastRetElt = null;
            } else {
                throw new IllegalStateException();
            }
            expectedModCount = modCount;
        }
    }
    扩容
    private void grow(int minCapacity) {
        int oldCapacity = queue.length;
        // 如果原尺寸小于64 则双倍扩容 反之扩容50%
        int newCapacity = oldCapacity + ((oldCapacity < 64) ?
                                         (oldCapacity + 2) :
                                         (oldCapacity >> 1));
        // 保证新尺寸小于Integer.MAX_VALUE 不然内存溢出
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        queue = Arrays.copyOf(queue, newCapacity);
    }
    基本操作
    //取堆顶元素
    public E peek() {
        return (size == 0) ? null : (E) queue[0];
    }
    添加元素
    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;
    }
    //调整插入 区分是否有自定义的比较器 没有则用对象默认实现的Comparable
    //k 默认插入位置 x 插入元素
    private void siftUp(int k, E x) {
        if (comparator != null)
            siftUpUsingComparator(k, x);
        else
            siftUpComparable(k, x);
    }
    private void siftUpComparable(int k, E x) {
        Comparable<? super E> key = (Comparable<? super E>) x;
        while (k > 0) {
            int parent = (k - 1) >>> 1;//(k-1)/2
            Object e = queue[parent];
            //当目标元素比父节点大时 停止向上比较
            if (key.compareTo((E) e) >= 0)
                break;
            //与父节点互换位置
            queue[k] = e;
            k = parent;
        }
        queue[k] = key;
    }
    ​
    @SuppressWarnings("unchecked")
    private void siftUpUsingComparator(int k, E x) {
        while (k > 0) {
            //找到k位置所在的父节点 
            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;
    }
    移除特定元素:如果有多个相等的 只删除第一个
    public boolean remove(Object o) {
        int i = indexOf(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;
            //将队尾元素先覆盖位置i 然后向下做调整
            siftDown(i, moved);
            if (queue[i] == moved) {
                siftUp(i, moved);
                if (queue[i] != moved)
                    return moved;
            }
        }
        return null;
    }
    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; // 假设左孩子比右孩子更小
            Object c = queue[child];
            int right = child + 1;
            if (right < size &&
                ((Comparable<? super E>) c).compareTo((E) queue[right]) > 0)
                c = queue[child = right];
            if (key.compareTo((E) c) <= 0)
                break;
            queue[k] = c;
            k = child;
        }
        queue[k] = key;
    }
    ​
    @SuppressWarnings("unchecked")
    private void siftDownUsingComparator(int k, E x) {
        int half = size >>> 1;//计算非叶子节点元素的最大位置
        while (k < half) {
            //得到位置k的左孩子
            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];
            //如果左/右孩子大于等于目标元素x 跳出循环
            if (comparator.compare(x, (E) c) <= 0)
                break;
            queue[k] = c;
            k = child;
        }
        //将x放入 k是叶子节点
        queue[k] = x;
    }

     

  • 相关阅读:
    PDF怎么转换为CAD文件?这两种方法你的会
    这可能最简单的一种PS图片特效,零基础小白教程
    CAD打印图纸要怎么操作?简单方法分享给你
    CAD画三维图怎么渲染?一分钟教你快速操作
    CAD绘图效率低?教你4个CAD绘图技巧,绘图效率提升十倍
    在CAD中进行圆角标注的方法
    CAD总记不住?设计达人给你支招,最强口诀40条玩转设计
    MATLAB的数据类型
    IDEA 2019 安装包及安装教程
    python——正则表达式
  • 原文地址:https://www.cnblogs.com/hangzhi/p/10594563.html
Copyright © 2020-2023  润新知