The previous sections describe the basic container classes in Java, with a data structure behind each container class, ArrayList is a dynamic array, LinkedList is a list, Hashmap/hashset is a hash table, Treemap/treeset is a red-black tree, This section describes another data structure-heap.
Introducing Heaps
Before we mentioned the heap, where the heap refers to the in-memory area, the dynamically allocated objects are saved, corresponding to the stack. The heap here is a data structure that is independent of the memory area and allocation.
What is the structure of the heap? We'll take a closer look later. Let's start by explaining what the heap is for. Why would you introduce it?
Heaps can be very efficient and convenient to solve many problems , such as:
- Priority queue, the queue implementation class LinkedList we introduced earlier is queued in addition order, but in reality, it is often necessary to prioritize, each time should handle the current queue of the highest priority, high priority, even if it comes late, it should be processed preferentially.
- Ask k the largest element, the number of elements is uncertain, the amount of data may be large, or even a steady flow, but need to know so far the largest first k elements. The variant of this problem is: ask K the smallest element, ask K the largest, seek the smallest of K.
- For the median element, the median value is not the average, but the value of the intermediate element after sorting, and the amount of data can be large or even steady.
The heap can also be sorted, called heap ordering, but there is a better sort algorithm, so we don't introduce its application in the sort.
There is a class priorityqueue in the Java container that represents the priority queue, which implements the heap, which we'll cover in detail in the next section. For the next two questions, how they are efficiently resolved using heaps, we will implement them in code and explain them in detail in the following sections.
With all the benefits, what is the heap?
Concept of the Heap
Complete binary Tree
The heap is first a binary tree, but it is a complete binary tree . What is a complete binary tree? Let's first look at another similar concept, full of two forks.
A two-fork tree means that, except for the last layer, each node has two children, and the last layer is a leaf node, and there are no children. For example, two binary trees are full of two fork trees.
A full two fork tree must be a completely binary tree, but a complete binary tree does not require the last layer to be full, but if dissatisfied, it requires that all nodes must be centered on the leftmost, left to right is continuous, the middle cannot be empty. For example, the following binary trees are completely binary trees:
The following are not completely binary trees:
Numbering and array storage
In a fully binary tree, you can give each node a number, numbering starts from 1 consecutively, from top to bottom, from left to right, as shown in:
Complete binary tree has an important feature, given any one node, can be directly calculated according to its number of parent node and child node number , if the number is I, the parent node number is I/2, left child number is 2*i, right child number is 2*i+1. For example, for the number 5th node, the parent node is 5/2 that is 2, the left child is 2*5 that is 10, the right child is 2*5+1 that is 11.
Why is this characteristic important? It makes the logical concept of the two-tree can be conveniently stored in the array , the element index in the array corresponding to the number of nodes, the tree parent-child relationship through its index relationship is implicitly maintained, do not need to be kept alone. For example, the logical binary tree in, is saved to the array, its structure is:
Parent-child relationships are implicit, for example, for the 5th Element 13, the parent node is the 2nd element 15, the left child is the 10th element 7, the right child is the 11th element 4.
This method of storing the binary tree is not the same as the TreeMap described earlier, in TreeMap, there is a separate inner class entry,entry with three references, pointing to the parent node, the left child, and the right child, respectively.
With the use of array storage, the advantages are obvious, space saving and high access efficiency.
Maximum heap/Minimum heap
Heap logic is conceptually a completely binary tree, and the use of arrays on physical storage, in addition to these two points, the heap has a certain order requirements.
Prior to the introduction of the ordered binary tree, the ordered binary tree is completely ordered, each node has a definite precursor and successor, and cannot have duplicate elements.
Unlike the sort binary tree, in the heap, there can be duplicate elements, the elements are not completely ordered, but for the parent-child nodes, there are certain order requirements, according to the order of two kinds of heap, one is the largest heap, the other is the smallest heap.
The maximum heap means that each node is not greater than its parent node. this way, for each parent node, it must be no smaller than all of its child nodes, and The root node is the largest of all nodes , and for each subtree, the root of the subtree is also the largest of all the nodes in the subtree.
The minimum heap is the exact opposite of the maximum heap, and each node is not smaller than its parent node. this way, for each parent node, it must not be greater than all of its child nodes, and The root node is the smallest of all nodes , and for each subtree, the root of the subtree is also the smallest of all the nodes in the subtree.
We look at the following:
Heap Concept Summary
To summarize, logically conceptually, a heap is a fully binary tree, with a specific order between parent and child nodes, divided into the largest heap and the smallest heap, the largest heap root is the largest, the minimum heap root is the smallest, and the heap is physically stored using an array.
Why is this data structure able to effectively solve the problem we said before? Before we answer, we need to look at how the basic operations of the data are performed on the heap, and how to keep the properties of the heap intact during the operation.
Algorithm of the heap
Below, let's look at how the basic operations of data are performed on the heap. The algorithm for the maximum heap and the minimum heap is similar, and we illustrate it with the smallest heap. Let's start by looking at how to add elements.
adding elements
If the heap is empty, add a root directly to the line. We assume that there is already a heap in which to add elements. The basic steps are:
- Add elements to the last position.
- Compared to the parent node, if the parent node is greater than or equal, the nature of the heap is satisfied, the end is otherwise swapped with the parent node, and then compared and exchanged with the parent node until the parent node is empty or greater than or equal to the parent node.
Let's look at an example. The following is the initial structure:
Adding element 3, after the first step, the structure becomes:
3 is less than the parent node 8 and does not satisfy the nature of the minimum heap, so swapping with the parent node becomes:
After swapping, 3 is still less than the parent node 6, so continuing the interchange will change to:
After the exchange, 3 is still less than the parent node, which is also the root node 4, to continue the exchange and become:
At this point, the adjustment is over, and the tree maintains the nature of the heap.
As can be seen from the above process, adding an element requires that the number of comparisons and exchanges be compared and exchanged up to the height of the tree, i.e. log2 (n) and N as the number of nodes.
This self-low-upward comparison, exchange, allows the tree to re-satisfy the nature of the heap process, which we call Siftup.
Remove an element from the head
In the queue, the general is to delete elements from the head, Java with the heap implementation of the priority queue, we see how to delete the head in the heap, the basic steps are:
- Replace the head element with the last element and delete the last element.
- Compare the new head to the smaller of the two child nodes, if not greater than the child node, then meet the nature of the heap, end it, otherwise swap with the smaller child, swap, and then compare and swap with the smaller child, until there is no child, or no more than two child nodes. This process is called Siftdown.
Let's look at an example. The following is the initial structure:
Performing the first step, replacing the head with the last element, will change to:
Now that the root node 16 is smaller than the child node, and the smaller child node 6 is replaced, the structure becomes:
16 or less than the child node, with a smaller child 8 exchange, the structure will become:
At this point, the nature of the heap is satisfied.
Remove an element from the middle
What if you need to remove a node from the middle? As with the deletion from the head, the element to be deleted is replaced with the last element first. However, after the replacement, there are two cases, if the element is larger than a child node, you need to adjust downward (siftdown), otherwise, if smaller than the parent node, you need to adjust upward (siftup).
Let's take a look at the example of removing a node with a value of 21, as shown in the first step:
After substitution, 6 has no child nodes, is less than the parent node 12, performs an upward adjustment of the siftup process, and the final result is:
Let's take another example to delete a node with a value of 9, as shown in the first step:
After swapping, 11 small less right operand children 10, so perform the siftdown process, after execution is completed:
Building the initial heap
Given an unordered array, how do you make it into a minimal heap? The process of turning a normal unordered array into a heap is what we call heapify.
The basic idea is that, starting from the last non-leaf node, go straight until the root, on each node, performs a downward adjustment of siftdown. In other words, it is the bottom-up, which is to make each of the first-child trees a heap, and then each pair of left and right subtrees and their parent nodes are merged and adjusted to a larger heap, because each subtree is already a heap, so the adjustment is to perform siftdown on the parent node, so that it is merged until the root. The pseudo-code for this algorithm is:
void heapify () { for (int i=size/2; I >= 1; i--) siftdown (i);}
The size represents the number of nodes, the node number starts at 1, and SIZE/2 represents the number of the first non-leaf node.
The time efficiency of this build is O (n) and N is the number of nodes, which is not proven.
Find and Traverse
There is no special algorithm for finding in the heap, which is to find the tail from the head of the array, and the efficiency is O (N).
Traversal in the heap is similar, the heap is an array, the traversal of the heap is the traversal of the array, the first element is the maximum value or the minimum value, but the following elements do not have a specific order.
It is necessary to note that the heap ensures that the output is orderly if the element is removed from the head one at a to one.
Algorithm Summary
These are the main algorithms for heap operations:
- When adding and removing elements, there are two key processes to maintain the nature of the heap, one to adjust upward (siftup) and the other to adjust downward (siftdown), all of which are O (log2 (N)). The process of building a heap from an unordered array heapify is a bottom-up loop, with an efficiency of O (N).
- Lookup and traversal are the lookup and traversal of an array, and the efficiency is O (N).
Summary
This section describes the basic concepts and algorithms of the heap data structure.
Heap is a more magical data structure, conceptually trees, storage arrays, father and son have a special order, the root is the maximum/minimum value, build/Add/delete efficiency is high, can effectively solve many problems.
But in Java, how is the heap implemented? The problems mentioned at the beginning of this article, how to solve the problem with the heap? Let's continue our exploration in the next few sections.
---------------
To be continued, check out the latest articles, please pay attention to the public number "old Horse Programming" (Scan the QR code below), from the introduction to advanced, in layman's words, Lao Ma and you explore the nature of Java programming and computer technology. Original intentions, All rights reserved.
Computer Program thinking Logic (45)-Magical heap