# Implementation of binary heap

Time：2021-11-24

### definition

A binary heap is a binary tree, i.e`Each node has only one parent node`also`Each node can have up to two child nodes`Tree structure. Binary heap is divided into maximum heap and minimum heap. If the value of any node in the heap is`Greater than or equal to`Its child nodes are called maximum heap. If the value of any node in the heap is`Less than or equal to`Its child nodes are called the minimum heap.

The binary tree in the following figure is a maximum heap, and each node in the tree has a`Greater than or equal to`Child nodes of this node:

#### Complete binary tree

Binary heap is a complete binary tree, that is, when a subtree has a right node, the subtree must have a left node. We will see that the nodes of this binary tree are arranged continuously from left to right. A more rigorous definition of a complete binary tree is:

If the depth of the binary tree is h, the number of nodes in all layers (1 ~ h-1) except layer h reaches the maximum, and all nodes in layer h are continuously concentrated on the left.

The following figure is a complete binary tree with nodes`Top to bottom, left to right`One node is stored in turn:

### basic operation

• Insert node: inserts a node into the binary heap.
• Take out the maximum (minimum) node: take out the root node of the binary heap.

### application

• Priority queue
• Heap sort
• solve`top K`problem

### Implementation of binary heap

The following specific implementations are`Take the maximum heap as an example`That is, the root node of the binary heap is greater than or equal to all its child nodes. The operation of the minimum heap is the same as that of the maximum heap, but the comparison relationship between nodes is different.

#### storage

Because the binary heap is a complete binary tree, we can use an array to store it. Each element of the array is each node in the binary heap. This is because the nodes of a complete binary tree are continuous from left to right. If it is not a complete binary tree, the indexes of nodes in the array will be discrete and discontinuous, which will waste memory space. When you want to store`N`When a binary stack of nodes, the length is`N+1`To store this binary heap. Array index is`1`The element is the root node of the binary heap. Indexes`0`The location of is empty. This is to facilitate the calculation of the indexes of the child nodes and parent nodes of each subtree.

If the index of a node of the tree in the array is k, then:

• Parent node index of this node: K / 2 (rounded down)
• Left child node index of this node: 2 * k
• Index of the right child node of this node: 2 * k + 1

The number on each node in the following tree represents the index of the node in the array, and the number in the node represents the element value corresponding to the node.

The tree is in the array`storage structure `Is:

Where the index is`3`The indexes of its parent and child nodes are:

• Parent node index:`3 / 2 = 1`(rounded down)
• Left child node index:`2 * 3 = 6`
• Right child node index:`2 * 3 + 1 = 7`

Binary heap initialization code implementation:

``````class BinaryHeap {
private:
//Array for storing binary heap
int *container = NULL;
//Capacity, that is, the maximum number of nodes can be stored
unsigned int capacity = 0;
//Size of binary heap
unsigned int size = 0;
public:
BinaryHeap(unsigned capacity) {
assert(capacity > 0);
//Initializes the array that holds the binary heap
this->container = new int[capacity];
this->capacity = capacity;
}
};``````

Index calculation code implementation

``````//Left child node index
unsigned calculateLeftChildIndex(unsigned index) {
return index * 2;
}
//Right child node index
unsigned calculateRightChildIndex(unsigned index) {
return this->calculateLeftChildIndex(index) + 1;
}
//Parent node index
unsigned calculateParentIndex(unsigned index) {
return index / 2; //  If both sides of C + + division are integers, it defaults to rounding down
}``````

#### Insert node

Inserting a node is to add a node to the heap, and the corresponding binary heap cannot be destroyed.

When inserting a node, first add the node to be inserted to the binary heap`Pile tail`(equivalent to adding a new element to the end of the array). At this time, the newly inserted node in the binary tree may be larger than its parent node, and the current binary tree no longer meets the definition of maximum heap. This node needs to be swapped with its parent node. After the exchange, the new parent node may still be larger than the parent node of the new parent node. Then repeat the previous operation again, moving up layer by layer until the heap top or the encountered node is no longer larger than its parent node. The operation of the entire switching node is called`shiftUp`, when the operation is completed, the binary tree meets the definition of maximum heap again.

The binary stack on the left of the figure below`Pile tail`Insert node`10`, get the tree on the right. Discover newly added nodes`10`Than its parent node`6`Even larger, the tree on the right violates the definition of binary heap and is no longer a binary heap. Therefore, we need to determine the location of the newly added node (that is, the node)`10`Where) do`shifUp`Operation:

In the tree on the left of the figure below`Node 10`Better than it`Parent node 6`To be large, they need to exchange positions to get the right tree:

In the tree on the left of the figure below`Node 10`Still better than it`Parent node 9`To be large, so they swap positions again to get the tree on the right:

`Node 10`Finally, it is moved to the root node, and any node in the observation tree is larger than its child nodes. In this way, the whole binary tree meets the definition of binary heap again. The whole process of repairing the binary tree is`shiftUp`Operation.

Insert node implementation code

``````    void insert(E element) {
assert(!this->isFull());
this->container[this->size] = element;
this->shiftUp(this->size);
this->size ++;
}``````

Shiftup implementation code

``````    void shiftUp(unsigned currentIndex) {
unsigned parentIndexOfCurrentIndex = this->calculateParentIndex(currentIndex);
while ((index > 1) && this->compare(this->container[index], this->container[parentIndexOfCurrentIndex])) {
swap(this->container[index], this->container[parentIndexOfCurrentIndex]);
currentIndex = parentIndexOfCurrentIndex;
parentIndexOfCurrentIndex = this->calculateParentIndex(currentIndex);
}
}``````

`while`Medium`index > 1`Indicates that the index is not a heap top index,`this->container[index] >= this->container[parentIndexOfCurrentIndex / 2]`Indicates that the node is larger than its parent node. As long as these two conditions are met at the same time, the location will be exchanged, and the index will be set as the parent node of the original node, moving up layer by layer until either of these two conditions is not met.

#### Delete node

When deleting a pin from a binary heap, only the node at the top of the heap can be deleted at a time. For the largest heap, it means deleting the largest node in the heap each time. If the heap is used to implement the priority queue, deleting a node from the heap can be understood as taking the node with the highest priority from the heap.

hold`Pile top`After the node is deleted, the`Pile tail`Node moved to`Pile top`The location of the. Generated in a new binary tree`Pile top`The node of may be smaller than its child nodes. At this time, the binary tree no longer meets the definition of binary heap. Need to put new`Pile top`The node of exchanges positions with the largest of its child nodes. After exchange`New child node`It’s still possible`New child node`If the child node is small, repeat the previous operation again. This moves down layer by layer until the encountered node is no longer smaller than its child nodes or to the bottom of the heap. The operation of the entire switching node is called`shiftDown`, when the operation is completed, the binary tree meets the definition of maximum heap again.

When deleting a pin from the tree on the left, find it first`Pile top`Positional`Node 10`, and then delete it to get the right tree:

Next, put the left in the tree`Pile tail`Positional`Node 6`Move to`Pile top`To get the right tree:

In the tree on the left`Pile top`Positional`Node 6`Better than it`Two child nodes`Even smaller, let the node exchange positions with the largest of its child nodes. Its two child nodes are`8`and`9`, the largest child node is`9`, so`Node 6`And`Node 9`Exchange positions and get the right tree after exchange:

After completing the above operation,`Node 6`There is no larger node in the child node of, so terminate the operation and finally get the tree in the figure below. It re satisfies the definition of binary heap.

Specific code

``````void shiftDown(unsigned currentIndex = 1) {
unsigned leftChildIndexOfCurrent = this->calculateLeftChildIndex(currentIndex);
//Judge whether the index of the left child node of the current node exceeds the size of the array. If it exceeds, it means that the node has no left child node
While (this - > getsize() > = leftchildindexofcurrent) {// if the node has left child nodes
unsigned maxChildIndexOfCurrent;
unsigned rightChildIndexOfCurrent = calculateRightChildIndex(currentIndex);
If (this - > getsize() > = rightchildindexofcurrent) {// if the node has a right child node
If (this - > container [rightchildindexofcurrent] > this - > container [leftchildindexofcurrent]) {// if the right child node is larger than the left child node
maxChildIndexOfCurrent = rightChildIndexOfCurrent; //  If the right child node is larger than the left child node, the largest child node is set as the right child node
} else {
maxChildIndexOfCurrent = leftChildIndexOfCurrent; //  Otherwise, the largest child node is set as the left child node
}
}
If ((this - > container [currentindex] > = this - > container [maxchildindex])) {// if the current node is greater than or equal to its largest child node, the definition of the largest heap is not broken, so just break it
break;
}
//If the current node has a child node larger than it, the positions of the two nodes are exchanged
swap(this->container[currentIndex], this->container[maxChildIndexOfCurrent]);
//Set the index of the current cycle as the index of the new root node, and then continue to check down
currentIndex = maxChildIndexOfCurrent;
leftChildIndexOfCurrent = this->calculateLeftChildIndex(currentIndex);
}
}``````

The code implementation idea is to judge first`Current node`Does it exist`Left child node`。 Then judge`Current node`Does it exist`Right child node`。 If it exists, find out the two child nodes`Largest child node`。 Then judge`Current node`whether`Greater than or equal to the largest child node in its child nodes`If the point is true, exit because it does not violate the definition of maximum heap. If it doesn’t work, it means`The current node has a child node larger than it`Then, the current node and its largest child node are exchanged, and the index of the current cycle is set as the index of the new root node, and then continue to check down.

#### Construction of binary reactor

hold`N`Elements are constructed into a binary heap.

hold`N`There are generally two ways to construct an element into a binary heap:

• The first method is through binary heap`Insert node`The operation inserts each element into the heap in turn.
• The second common way is to put this`N`The elements are stored in an array. At this time, you can think of the array as a`Complete binary tree`, but it’s not a binary heap yet. Then start back to the last element of the array in turn`shiftDown`The purpose of this step is to ensure that each subtree in the binary heap meets the definition of the binary heap. But we found that if a node is a`Leaf node`If so, it does not need to do any operation at all, because it has no child nodes, even if it does`shiftDown`Operation is not done. So after optimization, we can start from`The last node that has children`Start going back`shiftDown`。 The last node with children is also called`Non leaf node`, its index is`The parent node of the heap tail node`Index of. This method is called`heapify`

Heapify implementation

``````heapify(int *arr, unsigned size) {
//Size is the position at the end of the heap, and its parent node is the last node with children
for (int i = this->calculateParentIndex(size); i >= 1; i --) {
this->shiftDown(i);
}
}``````

#### Compatible with minimum heap and maximum heap

Sometimes we need as like as two peas, but sometimes we need to use the largest heap, but the two codes are almost the same, but the direction of the comparison symbol is different. In order to reuse the code, we only need to set a comparison method for the two fork heap, such as when it initializes the largest heap, it will bring in a method. This method is used for comparison. It is good to call this method when comparison is needed in binary heap.

If it is a minimum heap, our comparison method is as follows:

``````bool compare(int a, int b) {
return a < b;
}``````

For example, when calling at the corresponding place in the heap:

``````if (this->compare(this->container[calculateRightChildIndex(index)], this->container[calculateLeftChildIndex(index)])) {
// ........
}``````

### Conclusion

This paper expounds the definition and common operations of heap. The code in this paper uses C + +. The focus of data structure and algorithm is thought and logic, so you can use any language you are familiar with after understanding the idea of algorithm. An article on binary heap application and complexity analysis will be published later.

Complete code:https://github.com/acodercat/cpp-algorithm…

The binary heap in the warehouse code starts from index 0, so the calculation of the parent node index will be different.