当前位置: 首页 > article >正文

优先级队列(堆)

目录

优先级队列

堆的概念

堆的创建

堆的向下调整

堆的插入

完整代码


优先级队列

队列是一种先进先出的数据结构,有些时候操作的数据可能带有优先级,出队列时就需要优先级高的数据先出队列

在这种情况下,数据结构应该提供两个最基本的操作,一个是返回最高优先级对象,一个是添加新的对象。这种数 据结构就是优先级队列(Priority Queue)。

堆的概念

如果有一个关键码的集合K = {k0,k1, k2,…,kn-1},把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中,并满足:Ki = K2i+1 且 Ki >= K2i+2) i = 0,1,2…,则称为小堆(或大堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。

 

注意:

  • 已知孩子节点为i,则双亲节点为 (i-1)/2;
  • 已知双亲节点为i,左孩子:2*i+1;右孩子:2*i+2。

堆的创建

堆的向下调整

这里以大根堆为例来讲解堆的向下调整。

题目:对于集合{ 27,15,19,18,28,34,65,49,25,37 }中的数据,如果将其创建成大根堆呢?

 首先我们要定义基本变量,来供使用。因为是对于集合中的数据进行创建大根堆,所以我们可以使用数组来进行。

public class TestHeap {
    public int[] elem;
    public int usedSize;

    public TestHeap(){
        this.elem = new int[10];
    }
}

对于如何把数组中的数据放到实现堆的数组里,我们可以通过for循环来进行放置。

注意:这里是有两个数组。

    public void intelem(int[] array){
        for (int i = 0; i < array.length; i++) {
            this.elem[i] = array[i];
            usedSize++;
        }
    }

接着我们就要开始创建堆了

    public void createHeap(){
        for (int parent = (this.usedSize-1-1)/2; parent >= 0 ; parent--) {
            shifDown(parent, this.usedSize);//每棵树结束时候都给个10,如果接着调整的节点比10
                                            //大了,说明这棵树一定调整完了
        }
    }

主要的重心在于如何写出shifDown这个方法。

 思路:

  1. 由上面我们能知道 child = parent*2+1。为了确保child的数组不越界,我们要确定循环条件。
  2. 因为是创建大根堆,所以要找到左右子树的最大值同根节点进行比较、交换。
  3. 关于break,这里因为当 前一个节点已经结束了,下面的节点也是结束的状态。
 /**
     *
     * @param parent 每棵子树调整的起始位置
     * @param usedSize 判断 每棵子树 什么时候  调整结束
     */
    private void shifDown(int parent, int usedSize) {
        int child = 2*parent+1;
        while(child < usedSize){
            //找到左右子树的最大值
            if(child+1 < usedSize && elem[child] < elem[child+1]){
                child++;
            }
            if(elem[child] > elem[parent]){
               swap(elem,child,parent);
                parent = child;
                child = 2*parent+1;
            }else{
                break;
            }
        }
    }

    private void swap(int[] elem, int i ,int j){
        int tmp = elem[i];
        elem[i] = elem[j];
        elem[j] = tmp;
    }

通过Test测试类和调试,我们能看到大根堆创建成功了。

public class Test {
    public static void main(String[] args) {
        int[] array = {27,15,19,18,28,34,65,49,25,37};
        TestHeap testHeap = new TestHeap();

        //把array的值赋值给testHeap
        testHeap.intelem(array);
        testHeap.createHeap();
}

创建的堆下图,大根堆。

 

堆的插入

堆的插入总共需要两个步骤:

  1.  先将元素放入到底层空间中(注意:空间不够时需要扩容)
  2. 将最后新插入的节点向上调整,直到满足堆的性质

 其实这和上面的创建大根堆有些类似,但这里用到的是向上调整。

    //插入
    public void push(int val){
        if(isFull()){
            elem = Arrays.copyOf(elem,2*elem.length);
        }
        elem[usedSize] = val;
        sitUp(usedSize);
        usedSize++;

    }

    public boolean isFull(){
        return elem.length == usedSize;
    }
}

这里的关键在于向上调整部分代码的编写。

    private void sitUp(int child) {
        int parent = (child-1)/2;
        while(parent >= 0){
            if (elem[parent] < elem[child]){
                swap(elem,child,parent);
                child = parent;
                parent = (child-1)/2;
            }else{
                break;
            }
        }
    }

向上调整我们可以先确定孩子节点,最后一棵树的节点位置可以通过 useSize来确定,进而能确定双亲节点。

完整代码

TestHeap类

import java.util.Arrays;

public class TestHeap {
    public int[] elem;
    public int usedSize;

    public TestHeap(){
        this.elem = new int[10];
    }

    public void intelem(int[] array){
        for (int i = 0; i < array.length; i++) {
            this.elem[i] = array[i];
            usedSize++;
        }
    }

    public void createHeap(){
        for (int parent = (this.usedSize-1-1)/2; parent >= 0 ; parent--) {
            shifDown(parent, this.usedSize);//没棵树结束时候都给个10,如果接着调整的节点比10大了。说明这棵树一定调整完了
        }
    }


    //alt+p+enter 直接生成

    /**
     *
     * @param parent 每棵子树调整的起始位置
     * @param usedSize 判断 每棵子树 什么时候  调整结束
     */
    private void shifDown(int parent, int usedSize) {
        int child = 2*parent+1;
        while(child < usedSize){
            //找到左右子树的最大值
            if(child+1 < usedSize && elem[child] < elem[child+1]){
                child++;
            }
            if(elem[child] > elem[parent]){
               swap(elem,child,parent);
                parent = child;
                child = 2*parent+1;
            }else{
                break;
            }
        }
    }

    //插入
    public void push(int val){
        if(isFull()){
            elem = Arrays.copyOf(elem,2*elem.length);
        }
        elem[usedSize] = val;
        sitUp(usedSize);
        usedSize++;

    }


    private void swap(int[] elem, int i ,int j){
        int tmp = elem[i];
        elem[i] = elem[j];
        elem[j] = tmp;
    }


    private void sitUp(int child) {
        int parent = (child-1)/2;
        while(parent >= 0){
            if (elem[parent] < elem[child]){
                swap(elem,child,parent);
                child = parent;
                parent = (child-1)/2;
            }else{
                break;
            }
        }
    }

    public boolean isFull(){
        return elem.length == usedSize;
    }
}

Test类

public class Test {
    public static void main(String[] args) {
        int[] array = {27,15,19,18,28,34,65,49,25,37};
        TestHeap testHeap = new TestHeap();

        //把array的值赋值给testHeap
        testHeap.intelem(array);
        testHeap.createHeap();
        /*for (int i = 0; i < array.length; i++) {
            testHeap.push(array[i]);
        }
        testHeap.push(80);*/
    }
}


http://www.kler.cn/news/312776.html

相关文章:

  • 行业分析---自动驾驶行业的发展
  • MySQL定长窗口SQL
  • Spring为什么要用三级缓存解决循环依赖?
  • 微服务之服务注册与发现:Etcd、Zookeeper、Consul 与 Nacos 比较
  • libmodbus:写一个modbusTCP服务
  • 求Huffman树及其matlab程序详解
  • RabbitMQ 常见使用模式详解
  • Delta Lake
  • jetcache-阿里多级缓存框架神器一定要掌握
  • 【Kubernetes知识点】HPA如何控制不同的资源实现自动扩缩容?
  • 青柠视频云——如何开启HTTPS服务?
  • 最新植物大战僵尸杂交版V2.5版本【包含历史版本!持续更新!!】
  • 告别繁琐粘贴,CleanClip Mac 版,让复制粘贴变得简单快捷!粘贴队列功能太强大了!
  • Windows上,使用远程桌面连接Ubuntu
  • Java知识点小结3:内存回收
  • 2024.09.12校招 实习 内推 面经
  • Redis---关闭Redis服务端
  • 操作数组不越界的妙法C++
  • 光伏发电量估算有多重要?如何分析?
  • Java22-匿名变量/模式(Unnamed Variables Patterns)
  • k8s自动清理pod脚本分享
  • Web网站常用测试工具
  • Java【代码 18】处理Word文档里的Excel表格数据(源码分享)
  • 【系统架构设计师-2013年真题】案例分析-答案及详解
  • Leetcode 和为 K 的子数组
  • 【深度学习 Transformer VIT】Transformer VIT:拆解“视觉变形金刚”,笑谈技术细节
  • 【Android源码】屏蔽系统通知出现在系统栏中
  • C++速通LeetCode中等第7题-和为K的子数组(巧用前缀和)
  • 视频服务器:GB28181网络视频协议
  • python使用argparse解析命令行,如何正确传入科学计数法形式的浮点数