preface
Binary heap is a very famous data structure in computer science. It is often used in priority queue and heap sorting algorithm because it can find maximum and minimum values efficiently and quickly.
This article explains how binary heaps are implemented in TypeScript. Interested developers are welcome to read this article.
Writing in the front
This article focuses on how to implement heaps. For developers unfamiliar with the data structure of heaps, please refer to my other article: Data Structures: Heaps
Implementation approach
Binary heap is a special binary tree, binary heap is also called heap, it has the following two characteristics:
- It’s a complete binary tree
- A binary heap is either the smallest heap or the largest heap
Complete binary tree
A complete binary tree in which each layer has left and right children (except for the leaves of the last layer), and the leaves of the last layer are, as far as possible, left children.
The following diagram depicts a complete binary tree:
Minimum heap and maximum heap
- Minimum heap: All nodes are less than or equal to their children
- Maximum heap: All nodes are greater than or equal to their children
The following figure depicts the maximum heap and minimum heap
Implement binary heap
Binary heap can be represented in two ways:
- Represented by nodes like a binary tree
- Use array representation to retrieve values of parent, left, and right nodes by index value
The following figure illustrates two different representations
Operational heap node
We use arrays to represent binary heaps. For a node at a given position (index), we can do the following:
- Gets the left child node position of the given node: 2 * index + 1
- Get the position of the right child node of the given node: 2 * index + 2
- Gets the parent position of the given node :(index-1) / 2
Insert data into the heap
Insert into the heap refers to inserting data into the bottom leaf of the heap and siftUp, which means that we will swap the data with its parent until the parent is less than the inserted value.
- The INSERT method takes one parameter: the data to insert
- A non-null check is required on the inserted data, or false if null is returned
- Appending the data to be inserted to the end of the heap when the data is not empty
- After the insertion is complete, perform the siftUp operation to move the data to the appropriate location
- When the move is complete, it successfully inserted a piece of data into the heap, returning true
The implementation of the move up operation is as follows:
- The siftUp method takes a single parameter: the index of the inserted data.
- Gets the location of the parent node to insert data into.
- Swap nodes whose index is greater than 0 and whose heap[parent] > heap[index]
- Update index and parent, continue node swapping until heap[parent] < heap[index]
The implementation of the exchange is as follows:
- Swap takes three arguments: the array to operate on, the location of the element swapped, and the location of the element swapped
- Declare a temporary variable temp and assign the exchanged element
- The swapped element is assigned to the swapped element
- The swapped element is assigned the value temp
Next we use an example to illustrate the above insert process, as shown in the figure below for a minimum heap, where we insert a new node 2.
- Find its parent node 12, compare the size of 12 with that of 2, 12 > 2, and swap positions
- In this case, the parent of 2 is 5, which is greater than 2
- 2 the parent of 2 is 1,1 < 2, and the insert is complete
Find the maximum or minimum value in the heap
- The zero element of the array in the minimum heap is the minimum of the heap
- The zero element of the array in the maximum heap is the maximum of the heap
Export the minimum or maximum value in the heap
Removing the minimum (minimum heap) or maximum (maximum heap) means removing the first element in the array (the root of the heap).
After removal, we need to move the last element of the heap to the root and perform the siftDown function, which means we will swap elements until the heap is structurally sound.
- The extract function does not accept arguments
- Returns undefined if the heap is empty
- If the heap length is 1, return the top element directly
- Otherwise, declare a variable to hold the heap-top element
- Perform a drop function to adjust the heap structure
- Returns the top element of the saved heap
Implementation of the move down operation:
- The siftDown function takes one argument: the position of the element to be adjusted (index)
- Declare a variable (Element) to hold index
- Index (left, right, heap size);
- If heap[element] > heap[left], update element’s value to left
- If heap[element] > heap[right], update element’s value to right
- If the index! If == element, the index and element positions are swapped, continuing with the siftDown function
Next, we illustrate the above implementation with an example of a minimum heap
- We export the top of the heap node 1
- At this point, we need to put the last node of the heap on top of the heap
- At this point, move down to compare the size of 12 with its left child node 2, 12 > 2, and switch node position
- Continue the move down operation, compare the size of 12 with its left child node 5, 12 > 5, switch node position
- Index === element, the move down operation is complete, and the heap node is exported
Implement maximum heap
The above operation has realized a minimum heap, the difference between the maximum heap and the minimum heap lies in the comparison of nodes, so we only need to inherit the minimum heap, rewrite the comparison function, the original a and B comparison, b and A can be compared.
The implementation code
Above we explained the concept of heap, analysis of the implementation ideas, next we will be the above implementation ideas into code
- Create the heap. ts file
- Declare the MinHeap class, declare the heap, compare the function, initialize the heap
export class MinHeap<T> {
// Use arrays to describe a heap
protected heap: T[];
constructor(protected compareFn: ICompareFunction<T> = defaultCompare) {
this.heap = []; }}Copy the code
- Get left, right and parent node functions
// Get the position of the left child node
protected getLeftIndex(index: number) :number {
return 2 * index + 1;
}
// Get the position of the right child node
protected getRightIndex(index: number) :number {
return 2 * index + 2;
}
// Get the location of the parent node
protected getParentIndex(index: number) :number | undefined {
if (index === 0) {
return undefined;
}
return Math.floor((index - 1) / 2);
}
Copy the code
- Implement the insert function
insert(value: T): boolean {
if(value ! =null) {
// Add elements to the leaves of the heap, i.e. the end of the array
this.heap.push(value);
// Move the node up to the appropriate position
this.siftUp(this.heap.length - 1);
return true;
}
return false;
}
// Implement the upshift function
protected siftUp(index: number) :void {
// Get the parent node location
let parent = <number>this.getParentIndex(index);
// The insertion position must be greater than 0 and its parent must be greater than itself to perform the operation in the loop
while (index > 0 && this.compareFn(this.heap[parent], this.heap[index]) === Compare.BIGGER_THAN) {
// Swap the position of the elements
this.swap(this.heap, parent, index);
// Change the position of the currently inserted value to its parent node, and retrieve the position of the parent node, i.e. repeat the process until the root node of the heap has also been swapped
index = parent;
parent = <number>this.getParentIndex(index); }}// Implement the swap array element position function
protected swap(array: T[], exchangeElement: number, exchangedElement: number) :void {
// Use a temporary variable to hold the exchange element
const temp = array[exchangeElement];
// Assign the swapped element to the swapped element
array[exchangeElement] = array[exchangedElement];
// Assign the temporary variable saved in the first step to the swapped element
array[exchangedElement] = temp;
}
Copy the code
- Implement a minimum function that finds the heap
findMinimum(): T | undefined {
// Returns the smallest element of the array
return this.isEmpty() ? undefined : this.heap[0];
}
// Check whether the heap is empty
isEmpty(): boolean {
return this.size() === 0;
}
Copy the code
- Implements the minimum function for exporting the heap
extract(): T | undefined {
if (this.isEmpty()) {
return undefined;
}
if (this.size() === 1) {
// Returns the first element of the array
return this.heap.shift();
}
const removedValue = this.heap.shift();
// Perform the move down operation
this.siftDown(0);
return removedValue;
}
// Move down
protected siftDown(index: number) :void {
// Save the position of the current inserted value
let element = index;
// Get the position of its left and right child nodes
const left = this.getLeftIndex(index);
const right = this.getRightIndex(index);
const size = this.size();
// The element is valid and the current element is greater than its left child node
if (left < size && this.compareFn(this.heap[element], this.heap[left]) === Compare.BIGGER_THAN) {
element = left;
}
// The element is valid. The current element is greater than its right child node
if (right < size && this.compareFn(this.heap[element], this.heap[right]) === Compare.BIGGER_THAN) {
element = right;
}
// Find the location of the smallest node and verify that its value is the same as element
if(index ! == element) {// If not, swap it with the smallest element
this.swap(this.heap, index, element);
// Execute recursively
this.siftDown(element); }}Copy the code
Full code address: heap.ts
Heap sort
One application of heap is heap sort, which is not explained here. For developers who do not know heap sort, please refer to my other article: Sorting algorithm: Understanding and implementation of heap sort
- Implement heapsort functions
heapSort(array: T[]): void {
/ / build the heap
this.buildHeap(array);
// Start at the end of the heap, swap the iterated elements with 0 better elements, and move down
for (let i = array.length - 1; i >= 0; i--) {
this.swap(array, i, 0);
this.heapify(array, i, 0); }}/ / build the heap
private buildHeap(array: T[]) {
// Get the position of the last node
const last = array.length - 1;
const lastParent = <number>this.getParentIndex(last);
// Start heapify from the parent of the last node
for (let i = lastParent; i >= 0; i--) {
this.heapify(array, array.length, i); }}// Switch nodes
private heapify(array: T[], size: number, index: number) {
// Recursive baseline conditions
if (index >= size) {
return false;
}
// Find the left and right subtrees of the current node
const left = this.getLeftIndex(index);
const right = this.getRightIndex(index);
// Save the location of the node to be operated on
let element = index;
// Update element's value if the left child of the node being operated on is larger than its parent
if (left < size && this.compareFn(array[left], array[element]) === Compare.BIGGER_THAN) {
element = left;
}
Update element's value if the right child of the node being operated on is larger than its parent
if (right < size && this.compareFn(array[right], array[element]) === Compare.BIGGER_THAN) {
element = right;
}
// The position of element is not equal to the current node to operate on, swap element positions, recursive execution
if(element ! == index) {this.swap(array, element, index);
this.heapify(array, size, element); }}Copy the code
Write test code
Let’s test the above code to see if it works
import { MinHeap, MaxHeap } from "./lib/Heap.ts";
const minHeap = new MinHeap();
minHeap.insert(13);
minHeap.insert(10);
minHeap.insert(5);
minHeap.insert(7);
minHeap.insert(4);
minHeap.insert(17);
console.log("All elements of the heap (min)", minHeap.getIsArray());
console.log("Minimum heap (min)", minHeap.findMinimum());
console.log(minHeap.extract());
console.log(minHeap.getIsArray());
console.log("-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -");
const maxHeap = new MaxHeap();
maxHeap.insert(13);
maxHeap.insert(10);
maxHeap.insert(5);
maxHeap.insert(7);
maxHeap.insert(4);
maxHeap.insert(17);
console.log("All elements of the heap (Max)", maxHeap.getIsArray());
console.log(maxHeap.extract());
console.log("Maximum heap (Max)", maxHeap.findMinimum());
console.log("-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -");
const arrayTest = [12.15.17.18.4.5.1.7.19.20];
minHeap.heapSort(arrayTest);
console.log(arrayTest);
Copy the code
Write in the last
- If there are any errors in this article, please correct them in the comments section. If this article helped you, please like it and follow 😊
- This article was first published in nuggets. Reprint is prohibited without permission 💌