数据结构——树(1)——二叉堆

优先队列

我们回顾之前我们学过的队列,队列中的元素按照特定的顺序进行储存,并只能先进先出。然而,在现实生活中,我们却想把元素按照一定的优先级储存起来。举个现实中的例子:
- 我们平时坐高铁,会有所谓的头等舱,二等舱,普通舱。
- 在银行排队,总会有vip客户提前办理业务

所谓优先队列(priority queue),就是把元素按照一定的优先级储存起来,而不是根据特定的顺序。因此,它与我们之前接触的基于位置的数据结构有着本质的区别。因为这里并没有所谓的特定位置(类似于数组的下标)这个概念。

优先队列的基本操作

假设这里存在一个优先队列P,那么优先队列P应该有下面三个基本操作:

操作 功能
enqueue(k,e): 将优先级为k的元素e插入到P中。
dequeue(): 从P中删除具有最高优先级的元素。
peek(): 返回具有最高优先级键的P的元素(但是不从队列中删除)

优先级队列也有一些较少的的基本函数:

函数 功能
size(): 返回P中的元素数。
isEmpty(): Boolean测试P是否为空。
clear(): 清空队列。
peekPriority(): 返回最高优先级元素的优先级
changePriority(string value,int newPriority): 更改值的优先级。

可以看到,优先队列比我们传统的队列简单多了,因为我们不用考虑元素的位置问题,也就是说我们不用去实现复杂的insert,add功能。我们要做的只是,enqueue跟dequeue操作。原理如下
这里写图片描述

二叉堆(binary heap)

那么我们会怎么去实现我们的优先队列呢?可能第一的反应就是使用我们的链表吧,一个存储优先级一个存储我们的值,但是作为扩展,我们介绍一个更方便的结构——二叉堆.
堆,是一种基于树的结构,它具有以下属性:
父母的优先权要高于他们的孩子。
而一般的,我们有以下两种形式的堆:小根堆(左),大根堆(右)
这里写图片描述
最上面的那个点,我们称为它的根(root)。我们对于兄弟之间的顺序,并没有明确的规定,所以下图的两种情况都是小堆:
这里写图片描述
注意:小根堆的根一定是堆中最小的元素,而且他们的父亲一定是要小于他们的任一个儿子。大根堆中的根一定是堆中的最大的元素。且他们的父亲一定是要大于他们的任一个儿子。如下图,显然左边不是小堆右边才是:
这里写图片描述

当然,如果我们再仔细观察,我们可以发现,每一个堆除了最底层,都是充满的。因此,堆也是一种完全二叉树(complete binary trees)。那么什么又是完全二叉树?我们从它的命名来解释:
- 完全(complete):除了最后一层,其他层都是满的。
- 二叉(binary):每个父亲节点都只有两个儿子。

下图是一个堆,也是一个完全二叉树:
这里写图片描述

下一篇,提提堆的存储与构建。

猜你喜欢

转载自blog.csdn.net/redrnt/article/details/78366128
今日推荐