# [sitting on the toilet and looking at the algorithm] algorithm 12: heap - Magic priority queue

Then the last Pa said. How to build this heap. You can start with an empty heap, and then insert each element into the heap in turn until all the numbers are inserted (transferred to the heap). Because the time used to insert the ith element is O(log i), the overall time complexity of inserting all elements is O(NlogN), and the code is as follows.
``````n=0;
for(i=1;i<=m;i++)
{
n++;
h[ n]=a[ i];  //Or write it scanf("%d",&h[ n]);
siftup();
}``````

In fact, we have a faster way to build the heap. It's like this.

Directly put the 14 numbers 99, 5, 36, 7, 22, 17, 46, 12, 2, 19, 25, 28, 1 and 92 into a complete binary tree (here we still use a one-dimensional array to store the complete binary tree). In this complete binary tree, we start from the last node to determine whether the subtree with this node as the root conforms to the characteristics of the minimum heap. If all the subtrees conform to the minimum heap property, then the whole tree is the minimum heap. If you don't understand this sentence, don't worry. Keep reading.

First we start with the leaf node. Because the leaf node has no son, all the subtrees whose root node is the leaf node (in fact, this subtree has only one node) conform to the characteristics of the minimum heap (that is, the value of the parent node is smaller than that of the child node). These leaf nodes have no child nodes at all, which of course conforms to this feature. Therefore, all leaf nodes do not need to be processed and are skipped directly. Start from the n/2 node (n is the total number of nodes of the complete binary tree, here is node 7) to process the complete binary tree. Note that a complete binary tree has one property: the last non leaf node is the n/2 node.

The subtree with node 7 as its root does not conform to the characteristics of minimum heap, so it should be adjusted downward. Similarly, the subtrees with No. 6, No. 5 and No. 4 nodes as roots do not conform to the characteristics of the minimum pair, and need to be adjusted down. The following is the state after the adjustment of the subtree with No. 7, No. 6, No. 5 and No. 4 nodes as root nodes. Of course, at present, this tree still does not conform to the characteristics of the minimum heap. We need to continue to adjust the subtree with node 3 as the root, that is, node 3 is adjusted downward. Similarly, we continue to adjust the subtree with node 2 as the root, and finally adjust the subtree with root number 1 as its root. After adjustment, the whole tree conforms to the characteristics of minimum heap. Summarize the algorithm for creating the heap. To build a heap of n elements, first I can code these n nodes from 1 to N in a top-down, left to right way. In this way, the N nodes can be transformed into a complete binary tree. Then start from the last non leaf node (node No. n/2) to the root node (node No. 1), scan all nodes one by one, adjust the current node downward as required, until the subtree with the current node as the root node conforms to the heap characteristics. Although it's very complicated, it's very simple to implement. There are only two lines of code as follows:
``````for(i=n/2;i>=1;i--)
siftdown(i);``````
The time complexity of building a heap in this way is O(N). If you are interested, you can try to prove it yourself, hehe.
The heap also has the function of heap sorting, which has the same time complexity as quick sorting as O(NlogN). The implementation of heap sorting is very simple. For example, if we want to sort from small to large, we can first build a minimum heap, then delete the top elements every time and output them or put them into a new array until the heap is empty. The final output or the number stored in the new array is already sorted.
``````//Delete the largest element
int deletemax()
{
int t;
t=h[ 1];//Record the value of heap vertex with a temporary variable
h[ 1]=h[ n];//Assign the last point of the heap to the top of the heap
n--;//Heap elements reduced by 1
return t;//Returns the maximum number of previously recorded heap vertices
}``````

The complete code for heap building and heap sorting is as follows:
``````#include <stdio.h>
int h[ 101];//Array to hold the heap
int n;//Used to store the number of elements in the heap, that is, the size of the heap

//Exchange function to exchange the values of two elements in the heap
void swap(int x,int y)
{
int t;
t=h[ x];
h[ x]=h[ y];
h[ y]=t;
}

void siftdown(int i) //Pass in a node number to be adjusted down i，Here I pass in 1, which is to adjust downward from the top of the heap
{
int t,flag=0;//flag Used to mark whether further downward adjustment is needed
//When i When the node has a son (at least in the case of a left son) and needs to continue to adjust, it should be implemented circularly
while( i*2<=n && flag==0 )
{
//First, judge his relationship with his left son and use t Node number with lower record value
if( h[ i] > h[ i*2] )
t=i*2;
else
t=i;
//If he has a right son, discuss it again
if(i*2+1 <= n)
{
//If the value of the right son is smaller, update the smaller node number
if(h[ t] > h[ i*2+1])
t=i*2+1;
}
//If it is found that the minimum node number is not itself, it means that there are smaller nodes in the child node than the parent node
if(t!=i)
{
swap(t,i);//Exchange them, attention swap Functions need to be written by themselves
i=t;//to update i The number of the son node just exchanged with it for further downward adjustment
}
else
flag=1;//No indicates that the current parent node is smaller than both child nodes, and no adjustment is needed
}
}

//Functions to build the heap
void creat()
{
int i;
//Adjust upward from the last non leaf node to the first node in turn
for(i=n/2;i>=1;i--)
{
siftdown(i);
}
}

//Delete the largest element
int deletemax()
{
int t;
t=h[ 1];//Record the value of heap vertex with a temporary variable
h[ 1]=h[ n];//Assign the last point of the heap to the top of the heap
n--;//Heap elements reduced by 1
return t;//Returns the maximum number of previously recorded heap vertices
}

int main()
{
int i,num;
scanf("%d",&num);

for(i=1;i<=num;i++)
scanf("%d",&h[ i]);
n=num;

//Build a pile
creat();

//Delete top element, continuous delete n In fact, the night is from big to small
for(i=1;i<=num;i++)
printf("%d ",deletemax());

getchar();
getchar();
return 0;
}``````

You can enter the following data for verification
14
99 5 36 7 22 17 46 12 2 19 25 28 1 92
The result is
1 2 5 7 12 17 19 22 25 28 36 46 92 99

Of course, heap sorting is a better way. When sorting from small to large, the maximum heap is created instead of the minimum heap. After the maximum heap is established, the largest element is in H . Because our requirements are sorted from small to large, and we hope that the most important is at the end. So we exchange h  and H [n], where h [n] is the largest element in the array. Note that h  also needs to be adjusted down after swapping to maintain heap characteristics. OK now that the largest element has been returned, you need to reduce the heap size by 1, that is, n --, and then exchange h  and H [n], and adjust h  downward. Repeat this until the heap size becomes 1. At this point, the number in array h is sorted. The code is as follows:
``````//Heap sort
void heapsort()
{
while(n>1)
{
swap(1,n);
n--;
siftdown(1);
}
}``````

The complete heap sorting code is as follows. Note that using this method to sort from small to large requires building a maximum heap.
``````#include <stdio.h>
int h[ 101];//Array to hold the heap
int n;//Used to store the number of elements in the heap, that is, the size of the heap

//Exchange function to exchange the values of two elements in the heap
void swap(int x,int y)
{
int t;
t=h[ x];
h[ x]=h[ y];
h[ y]=t;
}

void siftdown(int i) //Pass in a node number to be adjusted down i，Here I pass in 1, which is to adjust downward from the top of the heap
{
int t,flag=0;//flag Used to mark whether further downward adjustment is needed
//When i When the node has a son (at least in the case of a left son) and needs to continue to adjust, it should be implemented circularly
while( i*2<=n && flag==0 )
{
//First, judge his relationship with his left son and use t Node number with larger record value
if( h[ i] < h[ i*2] )
t=i*2;
else
t=i;
//If he has a right son, discuss it again
if(i*2+1 <= n)
{
//If the value of the right son is larger, update the smaller node number
if(h[ t] < h[ i*2+1])
t=i*2+1;
}
//If it is found that the maximum node number is not itself, it means that there are larger nodes in the child node than the parent node
if(t!=i)
{
swap(t,i);//Exchange them, attention swap Functions need to be written by themselves
i=t;//to update i The number of the son node just exchanged with it for further downward adjustment
}
else
flag=1;//No indicates that the current parent node is larger than both child nodes, and no adjustment is needed
}
}

//Functions to build the heap
void creat()
{
int i;
//Adjust upward from the last non leaf node to the first node in turn
for(i=n/2;i>=1;i--)
{
siftdown(i);
}
}

//Heap sort
void heapsort()
{
while(n>1)
{
swap(1,n);
n--;
siftdown(1);
}
}

int main()
{
int i,num;
//Read in n number
scanf("%d",&num);

for(i=1;i<=num;i++)
scanf("%d",&h[ i]);
n=num;

//Build a pile
creat();

//Heap sort
heapsort();

//output
for(i=1;i<=num;i++)
printf("%d ",h[ i]);

getchar();
getchar();
return 0;
}``````

You can enter the following data for verification
14
99 5 36 7 22 17 46 12 2 19 25 28 1 92
The result is
1 2 5 7 12 17 19 22 25 28 36 46 92 99

OK, let's summarize. Data structures that support inserting elements and finding the largest (smallest) value elements like this are called priority queues. If you use ordinary queues to achieve these two functions, you need to enumerate the entire queue to find the largest element, which is a high time complexity. If an array has been sorted, inserting an element requires moving many elements, and the time complexity is still high. Heap is a priority queue implementation, which can solve these two operations well.

In addition, Dijkstra algorithm can also use heap to find the nearest vertex from the source point, so that the time complexity of the algorithm can be reduced to O((M+N)logN). Heaps are also often used to find the k-th largest number in a sequence. You only need to build a minimum heap of size k, and the top of the heap is the number K. If we want to find the k-th small number in a sequence, we only need to build a maximum heap with the size of K. the top of the heap is the k-th small number. The time complexity of this method is O(NlogK). Of course, you can also use the heap to find the number of the first k and the number of the first K. Can you come up with a faster algorithm? If you are interested, you can read section 5, Chapter 2 of the beauty of programming.

Heap sorting algorithm was invented by J.W.J. Williams in 1964. He also described how to use heap to implement a priority queue. In the same year, Robert W. Floyd proposed a linear time algorithm for building the heap.

BTW, Aha! The algorithm series, which can be read on the toilet, has been sorted out and published. This update is the last online update. You like Aha! Algorithm's friend is going to buy a search book It's not easy to write these days. Thank you for your support , Dangdang purchase link http://product.dangdang.com/23490849.html

The bought friend remembers to come what list, still can get "Aha!"! Algorithm T-shirt http://www.ahalei.com/thread-4969-1-1.html

Tags: Programming

Posted on Fri, 19 Jun 2020 00:10:39 -0400 by morris