• 优先级队列


    优先级队列使用二叉堆实现的

    插入元素和删除队列中最大的元素时间复杂度都是O(logn),因为这俩个操作是基于二叉堆的上浮和下沉操作实现的

    二叉堆是什么?

    二叉堆逻辑结构是完全二叉树,存储结构是数组

    二叉堆是怎么存的呢?

    // 父节点的索引
    int parent(int root) {
        return root / 2;
    }
    // 左孩子的索引
    int left(int root) {
        return root * 2;
    }
    // 右孩子的索引
    int right(int root) {
        return root * 2 + 1;
    }
    

    如图:数组索引0的位置专门置空

    优先级队列的实现

    public class MaxPQ {
        private Integer[] pq;
        // 当前 Priority Queue 中的元素个数
        private int N = 0;
    
        public MaxPQ(int cap) {
            // 索引 0 不用,所以多分配一个空间
            pq = new Integer[cap + 1];
        }
    
        public static void main(String[] args) {
            MaxPQ pq=new MaxPQ(5);
            pq.insert(5);
            pq.insert(4);
            pq.insert(3);
    
            System.out.println(pq.max());//5
            pq.delMax();
            System.out.println(pq.max());//4
            pq.insert(10);
            System.out.println(pq.max());//10
    
        }
    
    
    
        /* 返回当前队列中最大元素 */
        public int max() {
            return pq[1];
        }
    
        /* 插入元素 e */
        public void insert(int e) {
            N++;
            // 先把新元素加到最后
            pq[N] = e;
            // 然后让它上浮到正确的位置
            swim(N);
    
        }
    
        /* 删除并返回当前队列中最大元素 */
        public int delMax() {
            // 最大堆的堆顶就是最大元素
            int max = pq[1];
            // 把这个最大元素换到最后,删除之
            exch(1, N);
            pq[N] = null;
            N--;
            // 让 pq[1] 下沉到正确位置
            sink(1);
            return max;
        }
    
        /* 上浮第 k 个元素,以维护最大堆性质 */
        private void swim(int k) {
            // 如果浮到堆顶,就不能再上浮了
            while (k > 1 && less(parent(k), k)) {
                // 如果第 k 个元素比上层大
                // 将 k 换上去
                exch(parent(k), k);
                k = parent(k);
            }
    
        }
    
        /* 下沉第 k 个元素,以维护最大堆性质 */
        private void sink(int k) {
            // 如果沉到堆底,就沉不下去了
            while (left(k) <= N) {
                // 先假设左边节点较大
                int older = left(k);
                // 如果右边节点存在,比一下大小
                if (right(k) <= N && less(older, right(k)))
                    older = right(k);
                // 结点 k 比俩孩子都大,就不必下沉了
                if (less(older, k)) break;
                // 否则,不符合最大堆的结构,下沉 k 结点
                exch(k, older);
                k = older;
            }
    
        }
    
        /* 交换数组的两个元素 */
        private void exch(int i, int j) {
            int temp = pq[i];
            pq[i] = pq[j];
            pq[j] = temp;
        }
    
        /* pq[i] 是否比 pq[j] 小? */
        private boolean less(int i, int j) {
            return pq[i] < pq[j];
        }
        // 父节点的索引
        int parent(int root) {
            return root / 2;
        }
        // 左孩子的索引
        int left(int root) {
            return root * 2;
        }
        // 右孩子的索引
        int right(int root) {
            return root * 2 + 1;
        }
    
    }
    

    总结

    • 二叉堆就是一种完全二叉树,所以适合存储在数组中,而且二叉堆拥有一些特殊性质。

    • 二叉堆的操作很简单,主要就是上浮和下沉,来维护堆的性质(堆有序),核心代码也就十行。

    • 优先级队列是基于二叉堆实现的,主要操作是插入和删除。插入是先插到最后,然后上浮到正确位置;删除是调换位置后再删除,然后下沉到正确位置。核心代码也就十行。

  • 相关阅读:
    .ini文件的介绍及对其进行操作
    一些.net 控件使用的小细节
    三、类型设计规范
    [转]TimerCallback 委托
    [转]简单XML文件C#操作方法
    [转]用托盘控制windows服务的c#实现
    [转]DateTime相关
    [转]创建Windows服务 C#
    一、框架设计的基础
    [转]得到当前执行的函数名、码行、源代码文件名
  • 原文地址:https://www.cnblogs.com/treasury/p/12752861.html
Copyright © 2020-2023  润新知