内容介绍
树结构简介
树结构是计算机中常用的一种数据结构。我们先来看一下生活中的树:
计算机中的树和生活中的树是类似的,只不过是倒着的,树根在上,树叶在下。树上的每个组成元素都是一个节点,树根称为根节点
,树枝称为分支节点
,树叶称为叶子节点
,如下图所示:
二叉树结构简介
二叉树是:每个节点最多只能有两个子节点树。二叉树的子节点分为左节点和右节点,如下图:
满二叉树:如果该二叉树的所有叶子节点都在最后一层,并且节点总数= 2^n -1 , n 为层数,则我们称为满二叉树,如下图:
完全二叉树:如果该二叉树的所有叶子节点都在最后一层或者倒数第二层,而且最后一层的叶子节点在左边连续,倒数第二
层的叶子节点在右边连续,我们称为完全二叉树,如下图:
我们这里注意理解完全二叉树,因为堆结构是一种特殊的完全二叉树。关于树的结构,我们先简单介绍,以后会专门讲解树结构,我们这里主要是讲堆结构,所以先简单提及一下树结构。
堆结构简介
堆(Heap)是一种特殊的树形数据结构,每个结点都有一个值。常见的堆有二叉堆、斐波那契堆等,通常我们所说的堆的数据结构,是指二叉堆。如下图:
堆满足下列两个性质:
- 堆中某个节点的值总是不大于或不小于其父节点的值。
- 堆总是一棵完全二叉树。
根节点最大的堆叫做最大堆
或大根堆
,根节点最小的堆叫做最小堆
或小根堆
,如下图所示:
堆的存储
堆是非线性数据结构,可以使用一维数组来存储,将堆中序号对应的数据放到数组对应的索引中,如下图:
堆的一些概念和规律
概念:
- 某节点左边的子节点成为:左孩子。
- 某节点右边的子节点成为:右孩子。
- 某节点的上一个节点成为:父节点。
规律:假设当前节点的索引为i
- 父节点索引 = (i - 1) / 2 (Java中除以2取整数,比如7/2 = 3)
- 左孩子索引 = 2 * i + 1
- 右孩子索引 = 2 * i + 2
堆的定义性质:
- 最大堆节点的值大于左右孩子的值,也就是满足:
arr[i] > arr[2*i+1] && arr[i] > arr[2*i+2]
,如下图:
堆获取最大值
获取最大堆的最大值,其实就是获取堆中最前面一个元素。对于堆这种数据结构通常是将最前面的元素和最后面的元素换位置,最大值就到了最后一个位置,然后从堆中排除这个元素,当最后一个元素交换到最前面时,此时就不满足堆的性质了,我们需要将最前面这个元素通过ShiftDown
(下沉)的手段让堆继续满足堆的规则。
堆获取最大值可以分成两个步骤:
- 将堆中最前面的最大值和最后一个元素交换位置。
- 使用
ShiftDown
让最前面的元素下沉到合适的位置,依然满足堆的性质。
动画演示效果如下:
这里面重点注意,ShiftDown
可以让堆中的一个元素下沉到合适的位置,并且满足堆的规则。后面我们构建堆就需要使用到ShiftDown
操作。
ShiftDown
详细图解:
最大堆的最后一个非叶子节点
- 我们构建堆时需要从最后一个非叶子节点开始按照规则构建堆,所以我们需要知道最后一个非叶子节点计算公式:(堆的最大索引-1) / 2。