This commit is contained in:
krahets
2023-08-20 13:37:08 +08:00
parent 2e27ad1680
commit 44a8568356
32 changed files with 140 additions and 130 deletions
+8 -6
View File
@@ -4,17 +4,19 @@ comments: true
# 8.2   建堆操作
如果我们想要根据输入列表生成一个堆,这个过程被称为「建堆」。
在某些情况下,我们希望使用一个列表的所有元素来构建一个堆,这个过程被称为「建堆」。
## 8.2.1   借助入堆方法实现
最直接的方法是借助“元素入堆操作”实现首先创建一个空堆,然后将列表元素依次添加到堆中
最直接的方法是借助“元素入堆操作”实现。我们首先创建一个空堆,然后将列表元素依次执行“入堆”
设元素数量为 $n$ 则最后一个元素入堆的时间复杂度为 $O(\log n)$ 。在依次添加元素时,堆的平均长度为 $\frac{n}{2}$ ,因此该方法的总体时间复杂度为 $O(n \log n)$ 。
设元素数量为 $n$ 入堆操作使用 $O(\log{n})$ 时间,因此将所有元素入堆的时间复杂度为 $O(n \log n)$ 。
## 8.2.2   基于堆化操作实现
有趣的是,存在一种更高效的建堆方法,其时间复杂度仅为 $O(n)$ 。我们先将列表所有元素原封不动添加到堆中,**然后迭代地对各个节点执行“从顶至底堆化”**。当然,**我们不需要对叶节点执行堆化操作**,因为它们没有子节点
有趣的是,存在一种更高效的建堆方法,其时间复杂度可以达到 $O(n)$ 。我们先将列表所有元素原封不动添加到堆中,然后倒序遍历该堆,依次对每个节点执行“从顶至底堆化”
请注意,因为叶节点没有子节点,所以无需堆化。在代码实现中,我们从最后一个节点的父节点开始进行堆化。
=== "Java"
@@ -195,7 +197,7 @@ comments: true
为什么第二种建堆方法的时间复杂度是 $O(n)$ ?我们来展开推算一下。
- 完全二叉树中,设节点总数为 $n$ ,则叶节点数量为 $(n + 1) / 2$ ,其中 $/$ 为向下整除。因此,在排除叶节点后,需要堆化的节点数量为 $(n - 1)/2$ ,复杂度为 $O(n)$ 。
- 完全二叉树中,设节点总数为 $n$ ,则叶节点数量为 $(n + 1) / 2$ ,其中 $/$ 为向下整除。因此,在排除叶节点后,需要堆化的节点数量为 $(n - 1)/2$ ,复杂度为 $O(n)$ 。
- 在从顶至底堆化的过程中,每个节点最多堆化到叶节点,因此最大迭代次数为二叉树高度 $O(\log n)$ 。
将上述两者相乘,可得到建堆过程的时间复杂度为 $O(n \log n)$ 。**然而,这个估算结果并不准确,因为我们没有考虑到二叉树底层节点数量远多于顶层节点的特性**。
@@ -221,7 +223,7 @@ T(h) & = 2^0h + 2^1(h-1) + 2^2(h-2) + \cdots + 2^{h-1}\times1 \newline
\end{aligned}
$$
**使用错位相减法**,令下式 $2 T(h)$ 减去上式 $T(h)$ ,可得
使用错位相减法,用下式 $2 T(h)$ 减去上式 $T(h)$ ,可得
$$
2T(h) - T(h) = T(h) = -2^0h + 2^1 + 2^2 + \cdots + 2^{h-1} + 2^h
+4 -4
View File
@@ -324,7 +324,7 @@ comments: true
下文实现的是大顶堆。若要将其转换为小顶堆,只需将所有大小逻辑判断取逆(例如,将 $\geq$ 替换为 $\leq$ )。感兴趣的读者可以自行实现。
### 堆的存储与表示
### 1.   堆的存储与表示
我们在二叉树章节中学习到,完全二叉树非常适合用数组来表示。由于堆正是一种完全二叉树,**我们将采用数组来存储堆**。
@@ -565,7 +565,7 @@ comments: true
}
```
### 访问堆顶元素
### 2.   访问堆顶元素
堆顶元素即为二叉树的根节点,也就是列表的首个元素。
@@ -676,7 +676,7 @@ comments: true
}
```
### 元素入堆
### 3.   元素入堆
给定元素 `val` ,我们首先将其添加到堆底。添加之后,由于 val 可能大于堆中其他元素,堆的成立条件可能已被破坏。因此,**需要修复从插入节点到根节点的路径上的各个节点**,这个操作被称为「堆化 Heapify」。
@@ -1049,7 +1049,7 @@ comments: true
}
```
### 堆顶元素出堆
### 4.   堆顶元素出堆
堆顶元素是二叉树的根节点,即列表首元素。如果我们直接从列表中删除首元素,那么二叉树中所有节点的索引都会发生变化,这将使得后续使用堆化修复变得困难。为了尽量减少元素索引的变动,我们采取以下操作步骤: