A Binary (Max) Heap is a __complete binary tree__ that maintains the __Max Heap property__.

Binary Heap is one possible data structure to model an efficient __Priority Queue__ (PQ) Abstract Data Type (ADT). In a PQ, each element has a "priority" and an element with higher priority is served before an element with lower priority (ties are either simply resolved arbitrarily or broken with standard First-In First-Out (FIFO) rule as with a normal Queue). Try clicking for a sample animation on extracting the max value of random Binary Heap above.

To focus the discussion scope, this visualization show a Binary **Max** Heap of integers where duplicates are allowed. See __this__ for an easy conversion to Binary **Min** Heap. Generally, any other objects that can be compared can be stored in a Binary Max Heap, e.g., Binary Max Heap of floating points, etc.

**Remarks**: By default, we show e-Lecture Mode for first time (or non logged-in) visitor.

If you are an NUS student and a repeat visitor, please __login__.

**Complete Binary Tree**: Every level in the binary tree, except possibly the last/lowest level, is completely filled, and all vertices in the last level are as far left as possible.

**Binary Max Heap property**: The parent of each vertex - except the root - contains value greater than (or equal to) the value of that vertex. This is an easier-to-verify definition than the following alternative definition: The value of a vertex - except the leaf/leaves - must be greater than (or equal to) the value of its one (or two) child(ren).

Pro-tip 1: Since you are not __logged-in__, you may be a first time visitor (or not an NUS student) who are not aware of the following keyboard shortcuts to navigate this e-Lecture mode: **[PageDown]**/**[PageUp]** to go to the next/previous slide, respectively, (and if the drop-down box is highlighted, you can also use **[→ or ↓/← or ↑]** to do the same),and **[Esc]** to toggle between this e-Lecture mode and exploration mode.

Priority Queue (PQ) Abstract Data Type (ADT) is similar to normal Queue ADT, but with these two major operations:

- Enqueue(
**x**): Put a new element (key)**x**into the PQ (in some order), **y**= Dequeue(): Return an existing element**y**that has the highest priority (key) in the PQ and if ties, return any.

Discussion: Some PQ ADT reverts to First-In First-Out (FIFO) behavior of a normal __Queue__ in the event there is a tie of highest priority (key) in the PQ. Does guaranteeing stability on equal highest priority (key) makes PQ ADT harder to implement?

Pro-tip 2: We designed this visualization and this e-Lecture mode to look good on 1366x768 resolution **or larger** (typical modern laptop resolution in 2021). We recommend using Google Chrome to access VisuAlgo. Go to full screen mode (**F11**) to enjoy this setup. However, you can use zoom-in (**Ctrl +**) or zoom-out (**Ctrl -**) to calibrate this.

The content of this interesting slide (the answer of the usually intriguing discussion point from the earlier slide) is hidden and only available for legitimate CS lecturer worldwide. This mechanism is used in the various __flipped classrooms__ in NUS.

**If you are really a CS lecturer (or an IT teacher)** (outside of NUS) and are interested to know the answers, please drop an email to stevenhalim at gmail dot com (**show your University staff profile/relevant proof to Steven**) for Steven to manually activate this CS lecturer-only feature for you.

FAQ: This feature will **NOT** be given to anyone else who is not a CS lecturer.

Pro-tip 3: Other than using the typical media UI at the bottom of the page, you can also control the animation playback using keyboard shortcuts (in Exploration Mode): **Spacebar** to play/pause/replay the animation, **←**/**→** to step the animation backwards/forwards, respectively, and **-**/**+** to decrease/increase the animation speed, respectively.

Imagine: You are an __Air Traffic Controller (ATC)__ working in the control tower **T** of an airport. You have scheduled aircraft **X**/**Y** to land in the next 3/6 minutes, respectively. Both have enough fuel for at least the next 15 minutes and both are just 2 minutes away from your airport. You observe that your airport runway is clear at the moment.

✈(Y)

✈(X)

(T)

<--->

|||

|||

________|||_____________

In case you do not know, aircraft can be instructed to fly in __holding pattern__ near the airport until the designated landing time.

You have to attend the live lecture to figure out what happens next...

There will be two options presented to you and you will have to decide:

- Raise AND wave your hand if you choose option A,
- Raise your hand but do NOT wave it if you choose option B,

If none of the two options is reasonable for you, simply do nothing.

The content of this interesting slide (the answer of the usually intriguing discussion point from the earlier slide) is hidden and only available for legitimate CS lecturer worldwide. This mechanism is used in the various __flipped classrooms__ in NUS.

**If you are really a CS lecturer (or an IT teacher)** (outside of NUS) and are interested to know the answers, please drop an email to stevenhalim at gmail dot com (**show your University staff profile/relevant proof to Steven**) for Steven to manually activate this CS lecturer-only feature for you.

FAQ: This feature will **NOT** be given to anyone else who is not a CS lecturer.

The content of this interesting slide (the answer of the usually intriguing discussion point from the earlier slide) is hidden and only available for legitimate CS lecturer worldwide. This mechanism is used in the various __flipped classrooms__ in NUS.

**If you are really a CS lecturer (or an IT teacher)** (outside of NUS) and are interested to know the answers, please drop an email to stevenhalim at gmail dot com (**show your University staff profile/relevant proof to Steven**) for Steven to manually activate this CS lecturer-only feature for you.

FAQ: This feature will **NOT** be given to anyone else who is not a CS lecturer.

__flipped classrooms__ in NUS.

**If you are really a CS lecturer (or an IT teacher)** (outside of NUS) and are interested to know the answers, please drop an email to stevenhalim at gmail dot com (**show your University staff profile/relevant proof to Steven**) for Steven to manually activate this CS lecturer-only feature for you.

FAQ: This feature will **NOT** be given to anyone else who is not a CS lecturer.

__flipped classrooms__ in NUS.

**If you are really a CS lecturer (or an IT teacher)** (outside of NUS) and are interested to know the answers, please drop an email to stevenhalim at gmail dot com (**show your University staff profile/relevant proof to Steven**) for Steven to manually activate this CS lecturer-only feature for you.

FAQ: This feature will **NOT** be given to anyone else who is not a CS lecturer.

Now, let's view the visualisation of a (random) Binary (Max) Heap above. You should see a complete binary tree and all vertices except the root satisfy the Max Heap property (A[parent(i)] ≥ A[i]).

You can

between the visually more intuitive complete binary tree form or the underlying compact array based implementation of a Binary (Max) Heap.Quiz: **Based on this Binary (Max) Heap property, where will the largest integer be located?**

**N**)

**N = 2**所以

^{(h+1)}-1，

**h = log**

_{2}(N+1)-1 ~= log_{2}N。**N = 7 = 2**或者

^{(2+1)}-1**h = log**.

_{2}(7+1)-1 = 2A complete binary tree can be stored efficiently as a compact array A as there is no gap between vertices of a complete binary tree/elements of a compact array. To simplify the navigation operations below, we use 1-based array. VisuAlgo displays the index of each vertex as a red label below each vertex. Read those indices in sorted order from 1 to **N**, then you will see the vertices of the complete binary tree from top to down, left to right. To help you understand this, several times.

This way, we can implement basic binary tree traversal operations with simple index manipulations (with help of __bit shift manipulation__):

- parent(i) = i>>1, index i divided by 2 (integer division),
- left(i) = i<<1, index i multiplied by 2,
- right(i) = (i<<1)+1, index i multiplied by 2 and added by 1.

Pro tip: Try opening two copies of VisuAlgo on two browser windows. Try to visualize the same Binary Max Heap in two different modes and compare them.

In this visualization, you can perform several Binary (Max) Heap operations:

**Create(A)**- O(**N**log**N**) version (**N**calls of**Insert(v)**below)**Create(A)**- O(**N**) version**Insert(v)**in O(log**N**) — you are allowed to insert duplicates- 3 versions of
**ExtractMax()**:- Once, in O(log
**N**) **K**times, i.e.,**PartialSort()**, in O(**K**log**N**), or**N**times, i.e.,**HeapSort()**, in O(**N**log**N)**

- Once, in O(log
**UpdateKey(i, newv)**in O(log**N**if**i**is known)**Delete(i)**in O(log**N**if**i**is known)

There are a few other possible Binary (Max) Heap operations, but currently we do not elaborate them for pedagogical reason in a certain NUS module.

__flipped classrooms__ in NUS.

**If you are really a CS lecturer (or an IT teacher)** (outside of NUS) and are interested to know the answers, please drop an email to stevenhalim at gmail dot com (**show your University staff profile/relevant proof to Steven**) for Steven to manually activate this CS lecturer-only feature for you.

FAQ: This feature will **NOT** be given to anyone else who is not a CS lecturer.

**Insert(v)**: 当我们在往最大二叉堆插入元素 **v** 的时候 我们只能插入到最后一个元素* N + 1* 来维持一个紧凑的数组 = 完整二叉树特性。然而 最大堆的特性仍然可能没被满足。这时我们从插入点往上去修复最大堆特性（如果需要的话）直到整个堆符合最大堆特性。现在点 几次来插入几个随机的

**v**进去现在显示的最大二叉堆。

这个向上走并且修复最大堆特性的操作没有公认的名字。我们叫它 **ShiftUp** （上移）但是还有人叫它 **BubbleUp** 或者 **IncreaseKey** 操作.

__flipped classrooms__ in NUS.

**If you are really a CS lecturer (or an IT teacher)** (outside of NUS) and are interested to know the answers, please drop an email to stevenhalim at gmail dot com (**show your University staff profile/relevant proof to Steven**) for Steven to manually activate this CS lecturer-only feature for you.

FAQ: This feature will **NOT** be given to anyone else who is not a CS lecturer.

**Insert(v)** 的时间复杂度是 O(log **N**)。

讨论：你理解这个推论吗？

__flipped classrooms__ in NUS.

**If you are really a CS lecturer (or an IT teacher)** (outside of NUS) and are interested to know the answers, please drop an email to stevenhalim at gmail dot com (**show your University staff profile/relevant proof to Steven**) for Steven to manually activate this CS lecturer-only feature for you.

FAQ: This feature will **NOT** be given to anyone else who is not a CS lecturer.

**ExtractMax()**: 提取并删除最大二叉堆中的最大元素（根）的操作需要一个在堆中的元素来替换根，不然最大堆（一个完整的二叉树，在中文中的'林‘）会变成两个断开的子树（中文中两个'木’）。这同样也是这个元素必须是最后一个元素N的原因：维持紧凑数组 = 完整二叉树性质。

因为我们要把最大二叉堆中的一个叶顶点晋升成根顶点，它很可能是会违背最大堆特性。ExtractMax() 这时从根往下比较当前值和它的两个子元素的值（如果必要的话）来修复最大二叉堆特性。现在在当前显示的最大二叉堆中试试

这个向下走并修复最大堆特性的操作没有公认的名字。我们叫它 **ShiftDown** （下移）但是还有人叫它 **BubbleDown** 或者 **Heapify** 操作。.

__flipped classrooms__ in NUS.

**If you are really a CS lecturer (or an IT teacher)** (outside of NUS) and are interested to know the answers, please drop an email to stevenhalim at gmail dot com (**show your University staff profile/relevant proof to Steven**) for Steven to manually activate this CS lecturer-only feature for you.

FAQ: This feature will **NOT** be given to anyone else who is not a CS lecturer.

**ExtractMax()** 的时间复杂度是 O(log **N**)。

讨论：你理解这个推论吗？

__flipped classrooms__ in NUS.

**If you are really a CS lecturer (or an IT teacher)** (outside of NUS) and are interested to know the answers, please drop an email to stevenhalim at gmail dot com (**show your University staff profile/relevant proof to Steven**) for Steven to manually activate this CS lecturer-only feature for you.

FAQ: This feature will **NOT** be given to anyone else who is not a CS lecturer.

Up to here, we have a data structure that can implement the two major operations of Priority Queue (PQ) ADT efficiently:

- For
**Enqueue(x)**, we can use**Insert(x)**in O(log**N**) time, and - For
**y**= Dequeue(), we can use**y = ExtractMax()**in O(log**N**) time.

However, we can do a few more operations with Binary Heap.

**Create(A)**: 用含有 N 个逗号分隔的数组 A 从一个空的最大二叉堆开始创建一个合法的最大二叉堆

有两种方法完成创建操作一个简单但是慢 -> O(**N** log **N**) 另一个用更复杂的技术但是快 -> O(**N**).

教你一招：在两个浏览器里面同时打开 VisuAlgo。用最差情况 '已排序例子' 去执行不同版本的 Create(A)，你会看到可怕的差距。

**Create(A) - O(N log N)**: 单纯的一个接一个的插入 (用 **Insert(v) **操作的意思) 所有 **N** 个在输入数组中的元素进入到一个本来是空的最大二叉堆中。

**分析**: 这个操作显然是 O(**N** log **N**) 我们用了 O(log **N**) **Insert(v)** 操作 **N** 次. 让我们来研究 ’排好序的例子‘ 它是这个操作中比较复杂的例子之一（现在试试 我们显示了这个例子 **A=[1,2,3,4,5,6,7]** -- 请耐心等待 这个例子会比较耗时). 如果我们用递增的顺序往一个空的最大二叉堆中插入，每一次插入都会触发一次从插入点（新叶元素）到根的上移操作。

**Create(A) - O(N)**: 更快的版本 **Create(A)** 操作是 Robert W. Floyd 在 1964年发明的。 它利用了紧凑数组的优势 = 完整的二叉树和所有的叶元素（顶点的一半，见下页）生来就是最大二叉堆。然后这个操作只从最后一个内顶点一路回到根元素来修复最大二叉堆特性（如果必要的话）。

**分析**: 粗略分析我们得到 O(**N**/2 log **N**) = O(**N** log **N**) 但是它其实只是 O(2***N**) = O(**N**) — 下面几页会讨论细节。现在试试 用相同的输入数组 **A=[1,2,3,4,5,6,7]** 并且上一页那样观察（不是生成最多次调换的那个）这个版本要比 O(**N** log **N**) 版本厉害（快）得多.

简单证明为什么在最大堆中（里面N个元素）一半的元素都是叶元素（为了概括性，我们假设N是偶数）：

假设最后一个叶元素的序号是 **N**, 那么它的父元素的序号是 **i = N/2 **(回忆 __这节课__). 它的左子元素的序号是 **i+1**, 如果存在的话 (它其实并不存在), 将会是 **2*(i+1) = 2*(N/2+1) = N+2**, 这个结果超过了 **N** (最后一个叶元素) 所以 **i+1** 一定是一个没有子元素的叶元素。因为二叉堆的序号是连续的，所以序号s [**i+1 = N/2+1**, **i+2 = N/2+2**, ..., **N**], 或者说一半的顶点，都是叶元素。

**N**个元素的满二叉树的高度是log

_{2}

**N**.

**N**), 而是 O(

**h**)，h是在以顶点 i 为跟的从树的高度。

^{h+1})个顶点。

**N = 7，**

**h = 2。**顶点数量为

`ceil(7/2`分别是在

^{0+1}) = 4**h = 0**的 {44,35,26,17} 。在高度

**h = 1**有

`ceil(7/2`个顶点 分别是: {62,53} 在高度

^{1+1}) = 2**h = 2**有

`ceil(7/2`个顶点 它是 {71}。

^{2+1}) = 1堆排序函数**HeapSort()****：** John William Joseph Williams 在1964年发明了**堆排序算法**和这个二叉堆数据结构. 堆排序的操作 （假定最大二叉堆已经在**O(n)**的时间复杂度内建立）非常简单。只需要调用提取堆顶函数**ExtractMax() **n次即可，每次的时间复杂度为O(log **N**). 现在你可以试一下屏幕上的这个最大二叉堆

分析：

**堆排序**显然是O(

**N**log

**N**) - 一个最优的通过比较来排序的算法

Quiz: **In worst case scenario, HeapSort() is asymptotically faster than...**

Merge Sort

Insertion Sort

Selection Sort

尽管 **HeapSort()** 在最好/平均/最坏 情况下的时间复杂度都是 θ(**N** log **N**) ，它真的是最好的*用比较元素的方法*来实现的排序算法吗？

讨论点：**HeapSort()**的缓存性能如何？

__flipped classrooms__ in NUS.

**If you are really a CS lecturer (or an IT teacher)** (outside of NUS) and are interested to know the answers, please drop an email to stevenhalim at gmail dot com (**show your University staff profile/relevant proof to Steven**) for Steven to manually activate this CS lecturer-only feature for you.

FAQ: This feature will **NOT** be given to anyone else who is not a CS lecturer.

**K**个数，我们实际上可以调用O(log

**N**)的

**ExtractMax()**

**K**次。在目前显示的最大二叉堆上试试[未添加]。这个操作叫做

**PartialSort**() （部分排序）。

**PartialSort**() 的时间复杂度很明显是O(

**K**log

**N**)，复杂度取决于输出的大小。

当你全部学会了的时候，我们邀请你学习更高级的算法，它们用优先队做底层数据结构（之一），例如 __Prim's MST algorithm__, __Dijkstra's SSSP algorithm__, A* 搜索算法(还不在 VisuAlgo里), 一些贪婪算法，等等.

**i**，我们可以利用以下简单的策略：更新

**A[i] = newv**，然后

**shiftUp(i)**和

**shiftDown(i)**，只有一个恢复最大堆的动作会成功 - 如果

**newv**> / <

**A[parent(i)]/A[i更大的子值]**

**shiftUp(i)/shiftDown(i)**会被触发。

所以，

**UpdateKey(i, newv)**可以在O(log

**)内完成，如果我们已知序号**

**N**

**i**。**i**，我们可以利用以下简单的策略：更新

**A[i] = A[1]+1**（一个比当前根更大的值）。然后

**shiftUp(i)**（实际上是

**UpdateKey(i, A[1]+1)。**这样会使序号i变成新的根，然后我们可以

**ExtractMax()**一次来删除它。

**Delete(i)**可以在O(log

**)内完成，前提是我们已知序号**

**N**

**i**。

**和**

**UpdateKey(i, newv)****如果我们只有**

**Delete(i)，****，必须搜索它在最大二叉树中的的位置，会怎样？可以比O(**

**oldv****N**)更快吗？

__flipped classrooms__ in NUS.

**If you are really a CS lecturer (or an IT teacher)** (outside of NUS) and are interested to know the answers, please drop an email to stevenhalim at gmail dot com (**show your University staff profile/relevant proof to Steven**) for Steven to manually activate this CS lecturer-only feature for you.

FAQ: This feature will **NOT** be given to anyone else who is not a CS lecturer.

如果你在寻找一个最大二叉堆模型来构造优先队，好消息。

C++ 和 Java 已经有内置的优先队实现 它很有可能用的就是这个数据结构。他们是 __C++ STL priority_queue__ (默认的是最大优先队) 和 __Java PriorityQueue__ (默认是最小优先队). 然而这些内置的实现不一定适合我们高效的做一些优先队的扩展操作（因为NUS课程的原因，这里不谈细节）

Python有heapq，但是速度非常慢。OCaml没有内置的优先队列，但是我们可以用另一节课会提到的另一个数据结构来代替。

PS: 堆排序很可能会在 C++ STL 的 __partial_sort__用到

尽管如此，这里有我们的实现 __BinaryHeapDemo.cpp__.

我们还有一些编程问题可以用到二叉堆数据结构__UVa 01203 - Argus__ 和 __Kattis - numbertree__.

试着解决它们来提高你对这个数据结构的理解。你可以用C++ STL priority_queue, Python heapq或者JAVA PriorityQueue 如果它们可以简化你的解法

__flipped classrooms__ in NUS.

**If you are really a CS lecturer (or an IT teacher)** (outside of NUS) and are interested to know the answers, please drop an email to stevenhalim at gmail dot com (**show your University staff profile/relevant proof to Steven**) for Steven to manually activate this CS lecturer-only feature for you.

FAQ: This feature will **NOT** be given to anyone else who is not a CS lecturer.

__flipped classrooms__ in NUS.

**If you are really a CS lecturer (or an IT teacher)** (outside of NUS) and are interested to know the answers, please drop an email to stevenhalim at gmail dot com (**show your University staff profile/relevant proof to Steven**) for Steven to manually activate this CS lecturer-only feature for you.

FAQ: This feature will **NOT** be given to anyone else who is not a CS lecturer.

You have reached the last slide. Return to 'Exploration Mode' to start exploring!

Note that if you notice any bug in this visualization or if you want to request for a new visualization feature, do not hesitate to drop an email to the project leader: Dr Steven Halim via his email address: stevenhalim at gmail dot com.

__关闭__

-> 紧凑数组模式

创建(A) - O(**N** log **N**)

创建(A) - O(**N**)

插入(v)

提取最大值()

UpdateKey(i, newv)

Delete(i)