Skip to content

Commit 7257983

Browse files
committed
Heapsort fixes
1 parent e3c18d2 commit 7257983

File tree

3 files changed

+44
-24
lines changed

3 files changed

+44
-24
lines changed

src/algorithms/controllers/heapSort.js

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@ function isDownHeapkExpanded() {
4444
return areExpanded(['BuildHeap', 'DownHeapk']);
4545
}
4646

47+
// i, j (in sort) displayed only if second DownHeap is expanded
48+
function isDownHeap1Expanded() {
49+
return areExpanded(['SortHeap', 'DownHeap1']);
50+
}
51+
4752
export default {
4853
initVisualisers() {
4954
return {
@@ -133,7 +138,6 @@ export default {
133138

134139
chunker.add(4, (vis, index1, index2) => {
135140
vis.array.assignVariable('k', index1);
136-
// if (tmp != null) { // XXX looks dodgy using tmp here?
137141
if (index2 != null) {
138142
unhighlight(vis, index2);
139143
vis.array.removeVariable('j');
@@ -174,40 +178,44 @@ export default {
174178
// parent is greater than largest child, so it is already a valid heap
175179
if (A[i] >= A[j]) {
176180
heap = true;
177-
chunker.add(15, (vis, index, lastH) => {
181+
chunker.add(15, (vis, index, lastH, cur_k) => {
178182
unhighlight(vis, index, false);
179183
// possible last chunk in BuildHeap/DownHeapk
180184
// remove i, j if !isDownHeapkExpanded
181185
if (!isDownHeapkExpanded()) {
182186
vis.array.removeVariable('i');
183187
vis.array.removeVariable('j');
184188
}
185-
// remove k+highlighting if !isBuildHeapExpanded
186-
if (!isBuildHeapExpanded()) {
189+
// remove k+highlighting if !isBuildHeapExpanded & last
190+
// chunk of BuildHeap
191+
if (!isBuildHeapExpanded() && cur_k === 0) {
187192
vis.array.removeVariable('k');
188-
unhighlight(vis, lastH);
193+
if (lastH !== index)
194+
unhighlight(vis, lastH);
189195
}
190-
}, [j, lastiHighlight]);
196+
}, [j, lastiHighlight, k]);
191197
} else {
192198
swap = A[i];
193199
A[i] = A[j];
194200
A[j] = swap;
195201
swapAction(17, i, j);
196202
lastiHighlight = j;
197-
chunker.add(18, (vis, p, c, lastH) => {
203+
chunker.add(18, (vis, p, c, lastH, cur_k) => {
198204
unhighlight(vis, p, false);
199205
vis.array.assignVariable('i', c);
200206
// remove i, j if !isDownHeapkExpanded
201207
if (!isDownHeapkExpanded()) {
202208
vis.array.removeVariable('i');
203209
vis.array.removeVariable('j');
204210
}
205-
// remove k+highlighting if !isDownHeapkExpanded
206-
if (!isBuildHeapExpanded()) {
211+
// remove k+highlighting if !isDownHeapkExpanded & last
212+
// chunk of BuildHeap
213+
if (!isBuildHeapExpanded() && cur_k === 0) {
207214
vis.array.removeVariable('k');
208-
unhighlight(vis, lastH);
215+
if (lastH !== p)
216+
unhighlight(vis, lastH);
209217
}
210-
}, [i, j, lastiHighlight]);
218+
}, [i, j, lastiHighlight, k]);
211219
i = j;
212220
}
213221
}
@@ -220,7 +228,7 @@ export default {
220228
// clear variables & show 'n'
221229
vis.array.clearVariables();
222230
vis.array.assignVariable('n', nVal - 1);
223-
unhighlight(vis, index); // XXX skip for first loop iteration?
231+
unhighlight(vis, index);
224232
}, [n, i]);
225233

226234
let j;
@@ -286,6 +294,11 @@ export default {
286294
chunker.add(36, (vis, p, c) => {
287295
unhighlight(vis, p, false);
288296
vis.array.assignVariable('i', c);
297+
// remove i, j if !isDownHeap1Expanded
298+
if (!isDownHeap1Expanded()) {
299+
vis.array.removeVariable('i');
300+
vis.array.removeVariable('j');
301+
}
289302
}, [i, j]);
290303
i = j;
291304
}
@@ -294,10 +307,10 @@ export default {
294307
chunker.add(37, (vis) => {
295308
// Put in done state
296309
vis.array.clearVariables();
297-
vis.array.deselect(0);
310+
// vis.array.deselect(0);
311+
unhighlight(vis, 0, true);
298312
vis.array.sorted(0);
299313
vis.heap.sorted(1);
300-
unhighlight(vis, 0, true);
301314
});
302315
// for test
303316
return A;

src/algorithms/explanations/HSExp.md

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
---
44

55
Heapsort is a general purpose in-place sorting algorithm that has
6-
*<verbatim>O(n log n)</verbatim>* behavior in the worst case. It achieves
7-
this by first rearranging the array so it is a *heap* (which has some
6+
*<verbatim>O(n log n)</verbatim>* behavior in the worst case. It
7+
proceeds by first rearranging the array so it is a *heap* (which has some
88
ordering maintained; see below) then converting the heap into a sorted
99
array.
1010

@@ -17,12 +17,13 @@ the root in *<verbatim>A[1]</verbatim>* and the children of
1717
it's children (this is called the *heap condition*), thus the root is
1818
the maximum (heap sort uses a "max" heap; there are also "min" heaps
1919
where the ordering is reversed). Note that there are no pointers etc -
20-
we can view the array as a tree so as to understand the ordering.
20+
we can view the array as a tree so as to understand the ordering. In
21+
AIA, both views of this single data structure are displayed.
2122

2223
## Building a heap "bottom up"
2324

2425
The best way to build a heap from an unordered array is to first note that
25-
all the leaf nodes in the tree view are already heaps (they have no cildren
26+
all the leaf nodes in the tree view are already heaps (they have no children
2627
so the heap condition is satisfied), and work up the tree (backwards
2728
through the array) to the root. Each step combines two existing heaps
2829
plus their parent node to form a new heap (some rearrangement may be
@@ -32,23 +33,23 @@ needed; this is done by the *DownHeap* operation).
3233

3334
Sorting proceeds by repeating the following steps:
3435

35-
- swap the largest item (the root) with the last item in the array
36+
- swap the largest item (the root) with the last item in the heap
3637
- remove this largest item from further consideration (it is no longer
3738
considered part of the heap)
38-
- reform the remaining data items into heap order by performing
39-
*DownHeap* on the new root (note the two children of the root remain
40-
heaps)
39+
- rearrange the remaining data items into heap order by performing
40+
*DownHeap* on the new root (note the two children of the root are
41+
heaps before this step)
4142

4243
## The DownHeap operation
4344

4445
*DownHeap* traverses down the tree, swapping the data in the node with
4546
the maximum child of the node. It stops as soon as the data in the node
4647
is greater than or equal to the maximum child (or the node is a leaf).
47-
The time complexity is *O(log n)*
4848

4949
## Complexity
5050

51-
The worst case and nearly all other cases have time complexity *O(n log n)*.
51+
The time complexity of *DownHeap* is *O(log n)*. Overall for Heapsort
52+
the worst case and nearly all other cases have time complexity *O(n log n)*.
5253
Space complexity is O(1).
5354

5455

src/algorithms/extra-info/HSInfo.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,14 @@ Geeks for Geeks Link: [**Heap Sort**][G4GLink]
2020

2121
[G4GLink]: https://www.geeksforgeeks.org/heap-sort/
2222

23+
## Exercises/Exploration
24+
2325
Many teaching resources say the best case for Heap sort is O(n log n).
2426
However, there is a case where it is O(n) - can you figure out what it is?
27+
The AIA progress bar allows you to see how many steps there are in the
28+
animation, which is a *very rough* guide to run-time. For the best case,
29+
can you determine a formula for the number of steps taken with 2n data
30+
items, demonstrating it is O(n)?
2531

2632
Here we have presented the "bottom up" way of creating a heap from an
2733
unsorted array. There is also a "top down" method where we start with

0 commit comments

Comments
 (0)