优先级队列【堆】——数据结构

优先级队列(Priority Queue)

优先级队列:不同于先进先出队列,每次从队列中取出的是具有最高优先权的元素。
优先级队列相对于普通队列应该提供两个最基本的操作
(1) 返回最高优先级对象(2)添加新对象
在JDK8中的优先级队列底层使用了

堆的概念

堆的实质就是一个完全二叉树——并且堆中的节点遵循某个结点的值总是不大于或不小于其父结点的值
因此堆分为 大根堆小根堆

小堆:根节点最小的堆,满足Ki <= K2i+1Ki <= K2i+2

大堆:根节点最大的堆, 满足Ki >= K2i+1Ki >= K2i+2
如图:
在这里插入图片描述

堆的存储方式

堆是一棵完全二叉树,所以按照层序来看,可以采用顺序数组的存储方式

但是非完全二叉树就不适用于顺序存储了,因为非完全二叉树可能存在空节点,那么顺序存储也就存储这个空节点,造成空间上的浪费

i表示孩子结点,父亲结点**(i-1)/ 2**

i表示根节点 ,左孩子 2 * i + 1 右孩子 2 * i + 2

堆的创建(大根堆)

在这里插入图片描述

用堆模拟实现优先级队列(大根堆)

按顺序存储的方式,先写一个数组

   public int[] elem;
    public int userSize;//当前堆中有效的元素数据个数
 
    public MyHeap() {
        this.elem = new int[10];
        this.userSize = 0;
    }
 
    public void initArray(int[] array) {
        elem = Arrays.copyOf(array,array.length);
        userSize = elem.length;
    }
  1. 创建堆
    在这里插入图片描述具体代码实现:
  /**
     * @param parent: 每颗子树的根节点下标
     * @param len:每颗子树的结束位置
     * @description 向下调整
     */
    private void shiftDown(int parent,int len) {
        int child = 2*parent+1;//左孩子
        //必须要有左孩子
        while(child < len) {
            //如果一定有右孩子。那就判断 左孩子和右孩子大小,谁大保存谁
            if(child + 1 < userSize && 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[] array, int i, int j) {
        int tmp = array[i];
        array[i] = array[j];
        array[j] = tmp;
    }
    /**
     *建堆:大根堆
     *时间复杂度O(n)
     */
    public void createHeap() {
        for (int parent = (userSize-1-1)/2; parent >= 0 ; parent--) {
            shiftDown(parent,userSize);
        }
    }

分析一下建堆的时间复杂度O(n)
在这里插入图片描述

  1. 堆的插入
    在这里插入图片描述具体代码:
    public boolean isFull() {
        return userSize == elem.length;
    }
     //向上调整
    private void shiftUp(int child) {
        int parent = (child - 1) / 2;
        while(child > 0) {
            if(elem[child] > elem[parent]) {
                swap(elem,child,parent);
                child = parent;
                parent = (child - 1) / 2;
            }else {
                break;
            }
        }
    }
        //堆的插入
    public void offer(int x) {
        if (isFull()) {
            elem = Arrays.copyOf(elem,2*elem.length);
        }
        this.elem[userSize] = x;
        userSize++;
        shiftUp(userSize-1);
    }
  1. 堆的删除**(优先级队列删除,只能删除堆顶的元素)**
    在这里插入图片描述具体代码:
    public boolean isEmply() {
        return userSize == 0;
    }
      //堆的删除  只能删除堆顶元素
    public int poll() {
        if (isFull()) {
            return -1;
        }
        int old = elem[0];
        //1.交换
        swap(elem,0,userSize-1);
        //2.有效元素个数-1
        userSize--;
        //3.栈顶元素向下调整
        shiftDown(0,userSize);
        return old;
    }

课后作业题

1.已知小根堆为8,15,10,21,34,16,12,删除关键字8之后需重建堆,在此过程中,关键字之间的比较次数是

在这里插入图片描述2.最小堆[0,3,2,5,7,4,6,8],在删除堆顶元素0之后,其结果是 ()
A: [3 , 2 , 5 , 7 , 4 , 6 , 8] B: [2 , 3 , 5 , 7 , 4 , 6 , 8]
C: [2 , 3 , 4 , 5 , 7 , 8 , 6] D: [2 , 3 , 4 , 5 , 6 , 7 , 8]

经过变换得到的结果如图:
在这里插入图片描述最小堆结果为 [2 3 4 5 7 8 6 ]

这篇笔记就先写到这里,因为在慢慢补,后面的内容也会慢慢做笔记,循序渐进吧,关于优先级队列还有一些内容放到明天早上肝吧.加油,小孙!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
优先队列(priority_queue)是C++中的一种数据结构,它可以按照元素的优先级进行插入和删除操作。在C++中,优先队列默认使用vector作为底层存储数据的容器,并使用算法将vector中的元素构造成的结构。优先队列最常用的操作包括push、pop和top。 要遍历优先队列中的元素,可以使用while循环和empty函数来实现。首先,可以使用top函数获取优先队列中的最大(或最小)元素,并将其打印出来。然后,使用pop函数将该元素从优先队列中删除。重复这个过程,直到优先队列为空,即使用empty函数判断优先队列是否为空。在每次循环中,可以将获取的元素打印出来。 下面是一个示例代码来遍历优先队列: ```c++ #include <iostream> #include <queue> using namespace std; int main() { priority_queue<int> pq; pq.push(3); pq.push(8); pq.push(2); pq.push(6); pq.push(9); while (!pq.empty()) { cout << pq.top() << " "; pq.pop(); } cout << endl; return 0; } ``` 以上代码创建了一个优先队列pq,并依次插入了5个元素。然后使用while循环和empty函数遍历优先队列,每次输出顶元素,并将其从优先队列中删除,直到优先队列为空。最终输出的结果是按照从大到小的顺序输出了优先队列中的所有元素。 因此,c++优先队列的遍历可以通过循环的方式来实现。在每次循环中,使用top函数获取顶元素并打印,然后使用pop函数将其删除。重复这个过程直到优先队列为空。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [C++中算法(优先队列、遍历算法、查找算法、排序算法)](https://blog.csdn.net/qq_41915323/article/details/94664541)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [C++——优先级队列](https://blog.csdn.net/qq_55712347/article/details/128874870)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小孙的代码星球

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值