欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

优先级队列

程序员文章站 2024-02-14 14:13:04
...

1.通过优先级比较出队列,比如,手机玩游戏时,如果有电话打进来,那么系统先处理打进来的电话
2.java集合框架提供了两种类型的优先级队列,分别是:priorityqueue(非线程安全)priorityblockingqueue(线程安全)
3.注意:

  • priorityqueue中放置的元素必须要能够进行比大小,不能插入无法比较大小的对象,否则抛异常(ClassCastException异常
  • 不能插入null对象,否则会抛空指针异常
  • 没有容量限制,可以插任意多个元素, 其内部可以自动扩容
  • 插入和删除元素的时间复杂度为O(log2^N)
  • 底层使用了这种数据结构

4.优先级队列的构造

1.PriorityQueue()
创建了空的优先级队列,默认容量是11
2. PriorityQueue(int 初始容量)
创建带有初始容量的优先级队列,初始容量不能小于11,否则抛异常
3.PriorityQueue(Collection<? extends E> c)
用一个集合来创建优先级队列

static void TestPriorityQueue(){
 // 创建一个空的优先级队列,底层默认容量是11
 PriorityQueue<Integer> q1 = new PriorityQueue<>();
 // 创建一个空的优先级队列,底层的容量为initialCapacity
 PriorityQueue<Integer> q2 = new PriorityQueue<>(100);
 ArrayList<Integer> list = new ArrayList<>();
 list.add(4);
 list.add(3);
 list.add(2);
 list.add(1);
 // 用ArrayList对象来构造一个优先级队列的对象
 // q3中已经包含了三个元素
 PriorityQueue<Integer> q3 = new PriorityQueue<>(list);
 System.out.println(q3.size());
 System.out.println(q3.peek());
 }

优先级队列
4.优先级队列扩容的规则:

  • 如果容量小于64时,是按照oldCapacity*2 + 2的方式扩容的
  • 如果容量大于等于64,是按照oldCapacity*2的方式扩容的
  • 如果容量超过MAX_ARRAY_SIZE,按照MAX_ARRAY_SIZE来进行扩容

实现:

package queue;

import java.util.Arrays;
interface Compare{
    public int compare(int left,int right);
}

class Less implements Compare{
    //0:left==right
    //>0:left>right
    //<0:left<right
    public int compare(int left, int right){
        return left-right;
    }
}

class Greater implements Compare{
    public int compare(int left, int right){
        return right-left;
    }
}
//实现小堆
public class MyPriorityQueue {
    private int[] array;//存放数据
    private int size = 0;//优先级队列中有效元素的个数
    private Compare compare=null;
    /*public MyPriorityQueue(Compare comp) {
        //默认的构造,将其底层默认容量设置为11
        array = new int[11];
        size = 0;
        compare=comp;
    }*/

    /*public MyPriorityQueue(int initCapacity,Compare comp) {
        if (initCapacity < 1) {
            //标准库:抛出非法参数的异常
            //这里设置为11
            initCapacity = 11;
        }
        array = new int[initCapacity];
        size = 0;
        compare=comp;
    }*/

    //标准库中没有该接口--标准库中可以采用集合来构造优先级队列
    public MyPriorityQueue(int[] arr,Compare comp) {
        array = new int[arr.length];
        /*for (int i = 0; i < arr.length; i++) {
            array[i] = arr[i];
        }*/
        System.arraycopy(arr,0,array,0,arr.length);
        size = array.length;
        //将array中的元素进行调整,满足堆的特性
        //找到倒数第一个非叶子节点
        compare=comp;

        int lastLeaf = (array.length - 2) >> 1;
        for (int root = lastLeaf; root >= 0; root--) {
            shiftDown(root);
        }
    }

    //获取堆顶元素
    public int peek() {
        //标准库中,如果优先级队列是空,无法返回堆顶元素,返回null
        return array[0];
    }

    //获取优先级队列有效元素个数
    private int size() {
        return size;
    }

    //清空
    private void clear() {
        size = 0;
    }

    //插入
    private void offer(int x) {
        //插入元素之前需要判断是否需要扩容
        grow();
        array[size++] = x;
        shiftUp(size - 1);//注意:此处一定不能使用size--
    }

    //删除最小元素,堆顶元素
    int poll() {
        int ret = array[0];
        swap(0, size - 1);
        size--;
        shiftDown(0);
        return ret;
    }

    //判空
    boolean isEmpty() {
        return size == 0;
    }

    //只是模拟优先级队列扩容的一部分
    private void grow() {
        if (size >= array.length) {
            int oldCapacity = array.length;
            //扩容方式:原容量<64的:原容量的二倍加二,否则:原容量的1.5倍进行扩容
            int newCapacity = oldCapacity + ((oldCapacity < 64) ? (oldCapacity + 2) : (oldCapacity >> 1));
            array = Arrays.copyOf(array, newCapacity);//拷贝
        }
    }

    //调整的方法
    //调整以parent为根的二叉树,调整之前一定要保证左右子树已经满足小堆的性质
    //不满足就交换,交换后可能导致子树不满足堆的性质,继续调整子树
    public void shiftDown(int parent) {
        //如果要检测parent是否满足小堆的性质,只需要和孩子比较
        int child = parent * 2 + 1;//child标记较小的孩子,parent可能有左没有右孩子
        while (child < size) {
            //找parent左右孩子中较小的孩子
            // if(child + 1 < size && array[child + 1] < array[child]) {//保证右孩子存在,while循环条件已经保证左孩子存在
            if (child+1<size&&compare.compare(array[child+1],array[child])<0){
            child += 1;
            }
            //检测parent与较小孩子的大小
            //if (array[child] < array[parent]) {
            if (compare.compare(array[child],array[parent])<0){
                //不满足小堆性质
                swap(parent, child);
                //交换后可能破坏子树结构
                parent = child;
                child = parent * 2 + 1;
            } else {
                //满足
                return;
            }
        }
    }

    //向上调整
    public void shiftUp(int child) {
        int parent = (child - 1) >> 1;
        while (child != 0) {//或者parent
            //if (array[child] < array[parent]) {
            if (compare.compare(array[child],array[parent])<0){
                swap(parent, child);
                child = parent;
                parent = (child - 1) >> 1;
            } else {
                return;
            }
        }
    }

    //交换
    private void swap(int parent, int child) {
        int temp = array[parent];
        array[parent] = array[child];
        array[child] = temp;
    }

    public static void main(String[] args) {
        int[] array = {5, 3, 7, 1, 4, 6, 8, 0, 2};
        MyPriorityQueue mp = new MyPriorityQueue(array,new Greater());
        mp.offer(9);
        System.out.println(mp.peek());
        mp.offer(-1);
        System.out.println(mp.peek());
        System.out.println(mp.size());
        if (mp.isEmpty()){
            System.out.println("空");
        }else {
            System.out.println("非空");
        }
        while (!mp.isEmpty()){
            int temp=mp.poll();
            System.out.print(temp+" ");
        }

    }
}

上一篇: 可以提取表的结构信息

下一篇: