-
Notifications
You must be signed in to change notification settings - Fork 110
Heap lrc123 #18
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Lrc123
wants to merge
6
commits into
ojeveryday:docsify
Choose a base branch
from
Lrc123:Heap_Lrc123
base: docsify
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Heap lrc123 #18
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Binary file not shown.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| .DS_Store |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,84 @@ | ||
| # 优先队列和堆 | ||
|
|
||
| 作者: Lrc123 审核: liweiwei1419 | ||
|
|
||
| ## 什么是优先队列? | ||
|
|
||
| 「普通队列」的特点是:先进先出,后进后出。「优先队列」是一种特殊的「队列」,入队与普通队列无异,在出队的时候按照「优先级顺序」出队。这里的「优先级顺序」可以是人为定义的。「优先队列」可以使用数组实现,或者是维护有序数组,或者是在出队的时候,线性扫描找到优先级最高的元素,但是只要是「线性结构」,最差情况下都得扫描数组一遍。 | ||
|
|
||
| ## 为什么使用优先队列? | ||
|
|
||
| 这里要引出优先队列的一个特点:「动态」。如果应用场景是不需要有动态地添加和取出元素的话,我们只需要对容器进行一次性的排序就足以解决问题。比如对班级学生绩点进行从大到小依次输出,快速排序这样的排序算法效率要比使用优先队列来说要高得多。但是如果对手游王者荣耀中攻击范围内血量最低的敌人进行进攻的优先级排序,则需要使用到优先队列。因为攻击范围内的敌人数量是在不断变化的。如果要对变化中的容器每次都做整体的排序,效率是很低的($N$ 次调用是 $N^2\log N$ )。我们这里要讨论的是由「堆」这种数据结构所实现的优先队列,它的效率会要比排序法高上许多 ( $N$ 次调用是 $N\log N$ ) 。 | ||
|
|
||
|
|
||
| ## 什么是堆? | ||
|
|
||
| 为了避免「线性扫描」,需将数据组织成「树形结构」。二叉堆就是一种高效的「优先队列」实现。另外,还有二项式堆,最大-最小堆、斐波拉契堆等实现,针对普通的算法面试可以不用掌握。 | ||
|
|
||
| 二叉堆满足,从最大堆每次取出的堆顶元素是该堆中的最大元素,从最小堆每次取出的堆顶元素是该堆中的最小元素。在最大堆中,每一个父结点都是大于等于它的孩子结点。同理,最小堆则满足:每一个结点的值小于等于它的孩子结点(如果存在的话)的值。 | ||
|
|
||
|
|
||
| ## 二叉堆 | ||
|
|
||
liweiwei1419 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| 说到「二叉堆」,正如它名字所表示,它是一个使用二叉树来实现的数据结构。二叉树因其结构又有多种专有名词,我们这里对三种形态的二叉树做一个区分帮助大家理解。 | ||
liweiwei1419 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| ### 满二叉树 Full Binary Tree | ||
| 在国内普遍使用的教材《数据结构 c语言版》 (作者:「严敏蔚 吴伟民」)中,满二叉树的定义是:「 | ||
| 一棵深度为 $k$ 且有 $2^k - 1$ 个结点的二叉树称为满二叉树」。 | ||
| 那么它应该长这样: | ||
|  | ||
|
|
||
| 但是,根据[ wiki ](https://en.wikipedia.org/wiki/Binary_tree)等外文信息网站的描述: | ||
|  | ||
| 满二叉树的定义则是:「叶子结点的数量是非叶子结点数量加1的二叉树。」如上图,所以,当被问什么是满二叉树时。可以根据要求和语境作答。 | ||
|
|
||
| ### 完全二叉树 Complete Binary Tree | ||
| 完全二叉树的定义是:「除了最后一层不一定是满的,完全二叉树的每一层结点都是满的。且最后一层的结点是从左至右依次排列。当最后一层也是满的时候,也称作完美二叉树」。 | ||
|  | ||
|
|
||
| ### 完美二叉树 Perfect Binary Tree | ||
| 根据[ wiki ](https://en.wikipedia.org/wiki/Binary_tree)上的解释:「完美二叉树是所有非叶子结点都有左右两个孩子的二叉树,并且所有的叶子都有相同的高度」,又可以理解成最后一层是满的的完全二叉树,所以又可以说完美二叉树是特殊的完全二叉树。所以在这里,完美二叉树等于教材上的满二叉树。 | ||
|  | ||
|
|
||
| 后面我们只会用到完全二叉树,完全二叉树的定义以上文为准。 | ||
|
|
||
| ### 二叉堆图解 | ||
|
|
||
| >「二叉堆(Binary Heap)是一个可以被看成近似完全二叉树的数组。树上的每一个结点对应数组的一个元素。除了最底层外,该树是完全充满的,而且是从左到右填充」 <div style="text-align: right">—— 《算法导论》</div> | ||
|
|
||
| 上面这段引用什么意思呢,用一句话概括就是:`二叉堆在逻辑上是一颗完全二叉树,在实现上是普通的一维数组`。 | ||
| 正是由于二叉堆是完全二叉树,因此可以二叉堆使用一维数组作为实现。 | ||
|
|
||
| 我们用两幅图直观地感受一下「二叉堆」: | ||
|
|
||
|  | ||
| <center>图1. 最大堆和最小堆</center> | ||
|
|
||
liweiwei1419 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|  | ||
| <center>图2. 实现上的一维数组</center> | ||
|
|
||
|  | ||
| <center>图3. 直观表示</center> | ||
|
|
||
|
|
||
| ## 堆常见的操作: | ||
|
|
||
| HEAPPOP :弹出堆顶元素,并调整堆,替代到堆顶位置,时间复杂度为 $O(\log N)$ 。 | ||
|
|
||
| HEAPPUSH :向数组末尾加入新的元素,并调整到正确的位置,维持堆的结构,时间复杂度为 $O(\log N)$ 。 | ||
|
|
||
| HEAPIFY 建堆 :把一个无序的数组变成堆结构的数组,时间复杂度为 $O(N\log N)$ 。如果说 HEAPPOP 是动态地创建一个堆,那么 HEAPIFY 则是将一个数组一次转化成堆。具体的方法我们放在后面讲。 | ||
|
|
||
| HEAPSORT :HEAPFY 维持堆的结构,通过 HEAPPOP ,每次将最堆顶元素排列到堆尾, size 减小。重复操作直到数组绝对有序,时间复杂度为 $O(N\log N)$ 。空间复杂度为 $O(1)$ 。 | ||
|
|
||
|
|
||
| ## 学习建议 | ||
| + 我们可以先通过手动实现一个堆的数据结构来认识堆。 | ||
| + 当我们遇到题目中有优先级、大小关系或排序等字眼的时候,我们就可以想到堆这个数据结构,并尝试应用它。 | ||
|
|
||
| # 堆的应用和刷题常见问题 | ||
| + 堆与优先队列 | ||
| 堆与优先队列这个标题常常一起出现,实际上堆就是优先队列的一种实现方式。 | ||
| 我们在实例化优先队列的时候,也常常将实例名称写为 maxHeap 和 minHeap 。 | ||
| + 如果数据有动态更新的特点,可以使用「优先队列」(堆)。 | ||
| + `注意:这里的堆指的是一种数据结构,不是操作系统里的堆`。 | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.