数据结构——优先队列和堆

优先队列:

优先队列也是一个队列,他和普通队列的区别是:普通队列是先进先出,后进先出的;优先队列是出队顺序和入队顺序无关,和优先级相关。(如:医院看病时,病情最严重的那个需要先看病) 

实现优先队列同样底层也可以选择多种数据结构,

选择 普通的线性结构实现:出队O(1),入队O(n);

选择 顺序线性结构:入队O(n),出队O(1);

选择 堆实现:入队O(logn),出队O(logn); 下面我们就看一下堆这种数据结构。

堆: 

堆同样可以通过多种底层实现,这里我们主要看一下主流的,底层用二叉树实现的堆也称之为二叉堆。

特点:

二叉堆是一颗完全二叉树(完全二叉树:把元素顺序排列成树的形状,即元素一层一层的排列,排满当前层才排下一层)

堆中某个节点的值总是不大于其父亲节点的值(根节点的值为最大值),这样定义出来的叫最大堆,同理反过来也有最小堆。

实现:

扫描二维码关注公众号,回复: 4585247 查看本文章

由于是一颗完全二叉树,可以相应的给每个节点标号(层序),将它们放到一个数组中。

保存在数组中之后,就有一个问题,就是如何根据一个节点找他的孩子以及父亲节点,其实也很简单,看如下公式:

如果从数组下标为1开始存放:parent(i) =i/2  ;  left child(i) = 2i ; right child = 2*i+1

如果从数组下标为0开始存放:parent(i) =(i-1)/2  ;  left child(i) = 2i+1 ; right child = 2*i+2

添加元素(Sift Up):

首先将待添加元素插入末尾位置如图中52

但这样打破了堆的性质,每个节点都必须大于其孩子节点,那么接下来就将插入的节点和它的父亲节点作比较,如果大于其父亲节点,那么交换位置,然后再和当前父亲节点进行比较,如果父亲节点大继续交换,直到没有父亲节点,或者小于父亲节点为止,上图交换后如下:

取出元素Sift Dowm:

根据堆的性质只能取出最大的元素也就是堆顶的元素,同时取出后还需要保持堆的结构不被打破,那么我们进行如下操作:

先将堆末尾的元素放到堆的开头,如图中元素16

现在将堆顶元素(16)和它的两个孩子中较大的那个进行位置交换,然后再进行新一轮交换,直到没有孩子或者大于它的孩子中较大的那一个,上图操作完如下:

取出最大元素后,放入一个新的元素 replace:

可以直接将对顶元素替换以后进行 Sift Down,只需一次O(logn)的操作

 j注:ava中的PriorityQueue底层用的是最小堆

猜你喜欢

转载自blog.csdn.net/qq_28849965/article/details/85119648