数据结构学习笔记(一):Heap

来源:互联网 发布:unity3d 改变模型动画 编辑:程序博客网 时间:2024/06/01 08:27

数据结构学习笔记(一):Heap

本文提要

  • 什么是Heap
  • Heap的分类和特性
  • Heap的实现方法
  • Heap的主要操作
  • Heap在Java中的实现
  • 总结

什么是Heap?

Heap即为堆。它和stack(栈)一样,在计算机科学中都有两种完全不同的含义:在Operating System中,它是内存中的一块区域,而在数据结构中,它是一种树形的数据结构。这里所说的树形结构并不是指用二叉树来实现。事实上,heap通常用数组来实现,只是在视觉上表示成一个二叉树,这样会使得该结构更清晰,也更容易让人理解。例如下图就是heap的一个例子:

Heap

Heap的分类和特性

Heap主要分为最大堆和最小堆。最大堆所有节点的值都比其子节点的值要大,而最小堆则相反,所有节点的值都要比其子节点的值要小。

最大堆(图片来自www.tutorialspoint.com):

MaxHeap

最小堆(图片来自www.tutorialspoint.com):

MinHeap

Heap的实现方法

Heap可以通过数组来实现。以下图为例:

MinHeap

图中所示是一个最小堆,root的值(即最小值)为10。我们按照从上往下,从左往右的顺序将所有节点的值放入一个数组中,即可得到一个值为[10, 14, 19, 26, 31, 42, 27, 44, 35, 33]的数组。假设数组名称为heap,那么可以发现,节点i(即heap[i])的左子节点的index值为2i+1,右子节点的index值为2i+2。同理也可以得到节点i的父节点为(i-1)/2。

注:上面所说的index是从0开始计算的,如果你将root的index标记为1(即index从1开始),那么左右子节点的index值则为2i和2i+1,而父节点的index值为i/2。

Heap的主要操作

Heap的主要操作有:

  • Push
  • Pop
  • Remove

接下来说说这三种操作的具体实现以及时间复杂度,均以下图为例:

MinHeap

Push

Push即为将一个新的节点压入堆中。通常的做法是先将节点直接至于最后(如果用数组实现也就是数组的末尾),在通过不断地与父节点进行swap操作来将其置于正确的位置。Push的时间复杂度是O(log n)。

例如,如果我们想将12插入heap中,那么应该怎么做呢?

首先,将12插入heap末尾,即成为31的右子节点。将12与31进行比较,发现12比较小,因此将其与31进行调换。这时,12成为了14的右子节点,也是31和33的父节点。之后再将12与其父节点14进行比较,发现12更小,那么继续将12与14调换。然后再将12与父节点10进行比较,发现10更小,push操作结束。

Pop

Pop是将堆顶节点弹出。通常的做法是将堆顶节点与末尾节点对调,取出末尾节点后将新的堆顶节点与其子节点不断比较和对调,直到将其置于正确的位置中。由于过程与push类似,这里就不举例了。Pop的时间复杂度也是O(log n)。

Remove

Remove即移除某一节点(不一定是顶节点)。通常做法是先搜寻出目标节点,再将其与末尾节点对调,并将末尾节点置于正确的位置。Remove的时间复杂度主要取决于搜寻部分,如果是简单的对所有节点进行一边比较,那么时间复杂度为O(n);如果另外建立一个哈希表来存储节点值以及其位置信息(通常是指向目标节点的指针),那么搜寻部分的时间复杂度将会降到O(1),而总的时间复杂度也会因此降为O(log n),这也就是所谓的HashHeap。

Heap在Java中的实现

在Java中有一个名为PriorityQueue的class,实现的就是heap的数据结构。它有几个比较重要的method需要我们记住:

add()
即上文所说的push操作。

peek()
返回堆顶节点,但不将其从堆中取出。

poll()
返回堆顶节点,同时将其从堆中取出(即上文所说的pop操作)。

remove()
即上文所说的remove操作,时间复杂度为O(n)。

size()
返回堆中节点数量。

总结

Heap是一种常用的数据结构,主要用在需要快速得到某些元素中最大或最小值的情况下。

0 0
原创粉丝点击