优先级队列(堆)

1.优先级队列

1.1队列是一种先进先出的数据结构,但有的时候我们所操作的数据有这个优先级,可能需要优先级高的先出列,数据结构提供了俩个基本操作,一个是返回最高优先级对象,一个是添加对象。这种数据结构称为优先级队列。

2.优先级队列的模拟实现

jDk1.8中的priorityQueue底层使用了堆这种数据结构,堆本质上就是对二叉树的一些调整

2.1堆的概念

按完全二叉树的顺序存储方式(层序遍历规则)存储在一个一维数组里,每一个树的根结点最大,称为大根堆,每一个树的根结点最小,称为小根堆。

堆的性质

1.堆的某个节点的值总是不大于或者不小于父节点

2.堆总是一颗完全二叉树

2.2堆的存储方式

堆是一颗完全二叉树,因此可以按照层序的规则,然后顺序的去高效存储

2.3堆的创建

这里我们以创建大根堆为例子

当我们把这个数组创建好同时,传给了elem这个数组的时候,我们就要开始用这个数组的数据去创建大根堆

创建大根堆思路:1.我们要找到最后一个子树的父亲节点

                             2.当我们调整(向下调整)完最后一个子树后,我们该如何移动到下一个子树(子树的父亲节点下标减1)

                             3.什么时候调整完毕(结束条件)

说明:我们最后一个子树的父亲节点parent=(usedSize-1-1)/2,当parent等于0的时候就是顶部的了。

当面解决完一个子树移动到另一个子树的问题的时候,我们就得开写每一个子树向下调整的这个方法,我们说一下child<usedSize这个条件,我们的根据我们画图可知道,你在最后一个子树之后的节点,是根据parent,去求child,也就是parent*2+1,child不能大于usedSize

剩下的比较交换很简单,看我们图片的代码就行.

2.4大根堆的一些操作实现

1.在大根堆插入一些数据

说明:插入我们要将插入的数据插到,堆的末尾,也就是你一维数组的末尾,插完之后,我们进行向上操作。很简单看代码就可以理解。

2.删除大根堆(删除大根堆只能删完全二叉树的最上面的根结点,也就是把顶部的结点和最后的那个结点换一下,然后删除末尾那个结点就相当于删除了

说明:交换完成之后,记得向下操作,整成大根堆

3.常用接口的介绍

3.1priorityQueue的特性

java集合框架提供了priorityQueue和priorityBlockingQueue俩种类型的优先级队列,priorityQueue是线程不安全的,priorityBlockingQueue是线程安全的。

关于PriorityQueue的注意:

1.使用时必须导入PriorityQueue所在的包:import java.util.PriorityQueue;

2.PriorityQueue中放置的元素必须是能够比较的,不能放入无法比较的对象,否则会抛出ClassCastException异常(我们这里那一个student只定义类去验证)

PriorityQueue<Integer> priorityQueue = new PriorityQueue<>(new student())

这里会包异常ClassCastException异常,如果我们想传一个自定义类型的对象,我们需要实现让这个自定义类去实现Comparable接口,同时重写,这个接口里的compareTo方法,这样上面这个代码才不会报错。(为什么要实现Comparable这个接口,因为我们源码向上操作开始有一步强转Comparable<? super E>)


这里我们注意:当this在前是小根堆,在后是大根堆。(我们可以通过看源码得知),if(key.compareTo((E)e) >=0,compareTo我们在自定义类里重写了,逻辑就会不一样。

3.不能插入null对象,否则会抛出NullPointerException

4.没有容量限制,可以插入任意多个元素,其中内部可以自动扩容

需要扩容的时候,如果老的容量小于64就2倍扩容,大于等于64的时候就1.5倍扩容,还有一个是你定义是多少容量就是多少容量。

当我们调用的是这个无参构造函数的时候,我们编译器会给这个数组分配11个容量

5.插入和删除元素的时间复杂度为O(log2 N)

6.priorityQueue底层使用了堆数据结构

7.priorityQueue默认情况下是小堆

  自定义情况下this在前为小根堆,在后为大根堆

3.2比较器Comparator

说明:当我们自定义的这个类想根据它的age或者name的长度去比较,为了灵活的比较,我们要利用这个比较器,也就是让我们这个类去实现比较器的接口,重写里面的compare方法

比较器用的时候,实例化,然后传到PriorityQueue里面,它就会调用参数为构造器的那个构造函数。

3.4三种方式对比

Object.equals     所有类都是继承Object的,所有直接复写就行,不过只能比较相等于否

Comparable.compareTo   需要手动实现接口,请入性比较强,一旦实现,每次用该类都有顺序,属于内部顺序

Comparator.compare     需要实现一个比较器对象,对待比较类的侵入弱,但对代码实现侵入性强

oj题:

top-k问题

最大或最小的前k个数据。比如世界前500强

思路就是:如果我们求前k个最小的,我们就把先把数组里的前k个元素放到大根堆里,然后我们将顶部的top的元素和数组k位置的元素比较大小如果top大,我们就把top,poll出去,然后入k位置的元素,我们的priorityQueue会按默认的小根堆排序。

如果我们求前k个最大的,就建立小根堆,把数组前k个元素放进去,这里注意我们要写比较器去控制,PriorityQueue之后的排序是大根堆,放完之后,我们就比较top和k位置的数据,如果top小于k位置的数据,那么就把top出了,k位置数据入了。

堆的排序

我们这个数组从小到大排的话,我们就要建立一个大根堆,然后把最后一个放到顶部,顶部的放尾部,然后进行向下调整,然后从最后一个的前一个再进行上述操作即可

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值