数据结构之堆

news/2024/5/18 23:01:18 标签: 数据结构, java, 算法, , PriorityQueue, 1024程序员节

系列文章目录

数据结构PriorityQueue源码及特性分析 (大小根转换、扩容)_crazy_xieyi的博客-CSDN博客


文章目录

  • 前言
  • 一、是什么?
  • 二、的存储方式是什么?
  • 三、是怎么创建的?
  • 四、建的时间复杂度是多少?
  • 五、是怎么进行插入和删除元素的?
  • 六、用模拟实现优先级队列

前言

队列是一种先进先出 数据结构 ,但有些情况下, 操作的数据可能带有优先级,一般出队
列时,可能需要优先级高的元素先出队列,这个时候就需要带有优先级的数据结构,这种数据结构就是 优先级队列 (PriorityQueue)
JDK1.8 中的 PriorityQueue底层使用了数据结构 ,而实际就是在完全二叉树的基础之上进行了一些元素的调整。

一、是什么?

把所有元素按 完全二叉树 的顺序存储方式存储在一 个一维数组中,如果所有根节点 都不大于 左右孩子,则为小根;如果所有根节点 都不小于 左右孩子,则为大根
的性质如下:
1.中某个节点的值总是不大于或不小于其父节点的值
2.总是一棵完全二叉树

二、的存储方式是什么?

的概念可知,是一棵完全二叉树,因此可以层序的规则采用顺序的方式来高效存储。

注意:对于 非完全二叉树,则不适合使用顺序方式进行存储 ,因为为了能够还原二叉树, 空间中必须要存储空节 点,就会导致空间利用率比较低

三、是怎么创建的?(大根

1. parent 标记需要调整的节点, child 标记 parent 的左孩子 ( 注意: parent 如果有孩子一定先是有左孩子 )
2. 如果 parent 的左孩子存在,即 :child < usedsize , 进行以下操作,直到 parent 的左孩子不存在。
parent 右孩子是否存在,存在找到左右孩子中最大的孩子
parent 与较大的孩子 child 比较,如果:
parent大 于较大的孩子 child ,调整结束
否则:交换 parent 与较大的孩子 child ,交换完成之后, parent = child child = parent*2+1; 然后继续 2
java">    public void createHeap(){
        for (int parent = (usedSize-1-1)/2; parent >= 0 ; parent--) {
            shiftDown(parent,usedSize);
        }
    }

    /**
     * 每个根节点向下调整
     * @param parent     父节点
     * @param usedSize  调整的结束位置不能超过
     */
    public void shiftDown(int parent, int usedSize){
        int child = parent*2 + 1;
        while (child < usedSize){   //保证有左孩子
            if(child+1 < usedSize && elem[child] < elem[child+1]){ //保证有右孩子且大于左孩子
                child++;
            }

            if (elem[child] > elem[parent]){
                int temp = elem[child];
                elem[child] = elem[parent];
                elem[parent] = temp;
                parent = child;
                child = parent*2 +1;
            }else {
                break;
            }
        }
    }

四、建的时间复杂度是多少?O(n)

因为是完全二叉树,而满二叉树也是完全二叉树,此处为了简化使用满二叉树来证明 ( 时间复杂度本来看的就是近似值,多几个节点不影响最终结果) :(向下调整)

五、是怎么进行插入和删除元素的?

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

java">public void offer(int val){
        if (isFull()){
            elem = Arrays.copyOf(elem,2*elem.length);
        }
        elem[usedSize] = val;
        usedSize++;
        shiftUp(usedSize-1);
    }
    private void shiftUp(int child){
        int parent = (child - 1)/2;
        while (parent >= 0)
        if (elem[child] > elem[parent]){
            int temp = elem[parent];
            elem[parent] = elem[child];
            elem[child] = temp;
            child = parent;
            parent = (child - 1)/2;
        }else {
            break;
        }
    }
    public boolean isFull(){
        return elem.length == usedSize;
     }

的删除一定删除的是顶元素。具体如下:
1. 将顶元素对中最后一个元素交换
2. 将中有效数据个数减少一个
3. 对顶元素进行向下调整 

java"> public int pop(){
        if (isEmpty()){
            return -1;
        }
        int temp = elem[0];
        elem[0] = elem[usedSize-1];
        elem[usedSize-1] = temp;
        usedSize--;
        shiftDown(0,usedSize);
        return temp;
     }
     public boolean isEmpty(){
        return usedSize == 0;
     }
    /**
     * 每个根节点向下调整
     * @param parent     父节点
     * @param usedSize  调整的结束位置不能超过
     */
    public void shiftDown(int parent, int usedSize){
        int child = parent*2 + 1;
        while (child < usedSize){   //保证有左孩子
            if(child+1 < usedSize && elem[child] < elem[child+1]){ //保证有右孩子且大于左孩子
                child++;
            }

            if (elem[child] > elem[parent]){
                int temp = elem[child];
                elem[child] = elem[parent];
                elem[parent] = temp;
                parent = child;
                child = parent*2 +1;
            }else {
                break;
            }
        }
    }

六、用模拟实现优先级队列

java">public class MyPriorityQueue {
    public int[] elem;
    public int usedSize;

    public MyPriorityQueue() {
        this.elem = new int[11];
    }

    /**
     * 建的时间复杂度:
     *
     * @param array
     */
    public void createHeap(int[] array) {
        for (int i = 0; i < array.length; i++) {
            elem[i] = array[i];
            usedSize++;
        }
        int parent = (usedSize-1-1)/2;
        for (int i = parent; i >= 0; i--) {
            shiftDown(parent,usedSize);
        }
    }

    /**
     *
     * @param root 是每棵子树的根节点的下标
     * @param len  是每棵子树调整结束的结束条件
     * 向下调整的时间复杂度:O(logn)
     */
    private void shiftDown(int root,int len) {
        int child = root*2 + 1;
        while (elem[child] > elem[root]){
            if (child+1 < len && elem[child] < elem[child+1]){
                child++;
            }
            if (elem[child] > elem[root]){
                int temp = elem[child];
                elem[child] = elem[root];
                elem[root] = temp;
                child = root;
                root = (child-1)/2;
            }else {
                break;
            }
        }
    }


    /**
     * 入队:仍然要保持是大根
     * @param val
     */
    public void push(int val) {
        if (isFull()){
            elem = Arrays.copyOf(elem,2*elem.length);
        }
        elem[usedSize] = val;
        usedSize++;
        shiftUp(usedSize-1);
    }

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

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

    /**
     * 出队【删除】:每次删除的都是优先级高的元素
     * 仍然要保持是大根
     */
    public void pollHeap() {
        if (isEmpty()){
            return;
        }
        int temp = elem[0];
        elem[0] = elem[usedSize-1];
        elem[usedSize-1] = temp;
        usedSize--;
        shiftDown(0,usedSize);
    }

    public boolean isEmpty() {
        return usedSize == 0;
    }

    /**
     * 获取顶元素
     * @return
     */
    public int peekHeap() {
        if (isEmpty()){
            System.out.println("队列为空!");
            return -1;
        }
        return elem[0];
    }
}


http://www.niftyadmin.cn/n/720.html

相关文章

J-Tech Talk 活动预告|近似最近邻搜索算法 HNSW 的改进与优化

J-Tech Talk由 Jina AI 社区为大家带来的技术分享工程师们将深入细节地讲解具体的问题分享 Jina AI 在开发过程中所积累的经验针对海量向量数据的搜索&#xff0c;无论是工业界还是学术界都做了大量的研究。由于精确的向量搜索在海量数据的场景下搜索时间过长&#xff0c;所以目…

研一Python基础课程第三周课后习题分享(下)(含源代码)

这里分享剩余的八道题&#xff0c;比起前八道&#xff0c;后面八道题相对容易很多&#xff01; 一、题目分享 第九题&#xff1a;计算圆周率——无穷级数法 描述‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬…

基于Matlab使用跟踪筛选器跟踪机动目标仿真(附源码)

此示例演示如何使用各种跟踪筛选器跟踪机动目标。该示例显示了使用单个运动模型和多个运动模型的滤镜之间的差异。 一、定义方案 在此示例中&#xff0c;定义了一个目标&#xff0c;该目标最初以 200 m/s 的恒定速度行进 33 秒&#xff0c;然后输入 10 度/秒的恒定转弯。转弯…

Javascript | 用Javascript编写Python内置函数查询工具

最近在学习Python语言&#xff0c;Python有丰富的内置函数实现各种功能&#xff0c;但查询内置函数时总是需要百度查&#xff0c;有没有一个小工具可以单机无网络查询Python内置函数&#xff0c;方便自己学习编写Python程序呢&#xff1f;在网上查了一下好像没有&#xff0c;那…

[CSS]浮动

前言 系列文章目录&#xff1a; [目录]HTML CSS JS 根据视频和PPT整理视频及对应资料&#xff1a;HTML CSS 老师笔记&#xff1a; https://gitee.com/xiaoqiang001/html_css_material.git视频&#xff1a;黑马程序员pink老师前端入门教程&#xff0c;零基础必看的h5(html5)css3…

Python爬虫入狱小技巧

呀&#xff0c;来坐牢的是吧&#xff0c;坐牢是不可能坐牢的&#xff0c;骚年&#xff0c;下面就是方法&#xff0c;早上学&#xff0c;晚上进去 一、整体思路 爬虫一开始要把思路理清楚&#xff0c;即从网页源代码或者网页数据接口&#xff0c;获取需要的数据.大致思路如下 …

网络工程师视角下的“1024”

1B&#xff08;byte&#xff09;字节8Bit&#xff08;binary digit&#xff09;位 1KB&#xff08;KiloByte&#xff09;1024B(字节) 1MB&#xff08;MegaByte&#xff09;1024KB 1GB&#xff08;GigaByte&#xff09;1024MB 1TB&#xff08;TeraByte&#xff09;1024GB 1…

C语言题解 | 消失的数字轮转数组

… &#x1f333;&#x1f332;&#x1f331;本文已收录至&#xff1a;C语言题解系列 更多知识尽在此专栏中&#xff01; &#x1f389;&#x1f389;&#x1f389;欢迎点赞、收藏、关注 &#x1f389;&#x1f389;&#x1f389;文章目录&#x1f349;前言&#x1f349;正文&…