[C Language] Detailed explanation of heap sorting


For what is a heap, the conceptual classification of heaps and the two upward and downward adjustment algorithms of heaps can be seen: Creation of heaps

Insert image description here

1. Heap sorting idea

int a[] = {
    
     2,3,5,7,4,6 };

For such an array, if you want to use heap sort to sort it, the first thing to do is to use the data in the array to create a heap. Either a large heap or a small heap can be used. Heap sort can only be used if it is a heap.

So should we build a large heap or a small heap? For example, if we want to sort this array in ascending order, if we build a small heap
Insert image description here

After the small heap is built, the smallest element is found. To find the next smallest element, the remaining elements need to be regarded as a heap. However, the remaining elements are not necessarily heaps. The heap needs to be rebuilt, which is relatively expensive.

A better way is to build a large heap in ascending order, swap the top of the heap with the last element, and the last largest element is already in order. Adjust the remaining data downward to find the second largest one, and then you can Sort the array.

To summarize, the idea of ​​heap sorting is:
1. Build a large or small heap according to the order to be sorted. At this time, the element at the top of the heap is the maximum value. 2.
Exchange the top element and the last element. At this time, the last element is in order. There are n-1 elements left
. 3. Build the remaining n-1 elements into a heap again, and then exchange the top element of the heap with the n-1th element. Repeat this to get an ordered array.

Ascending order: build a large pile
Descending order: build a small pile

2. Adjust heap building sorting upward

Heap sort using upward adjustment algorithm to build heap

For example:Arrange array a from small to large (ascending order) using heap sort

Insert image description here
First, use the upward adjustment algorithm to build a large heap. For this method, please refer to the creation of a heap.

The prerequisite for the upward adjustment algorithm is: the previous element is a heap

A single node can be regarded as a large heap, so the array elements can be adjusted sequentially through the upward adjustment algorithm. The element to be adjusted must be preceded by a heap, and the conditions are met.

Insert image description here

The created big pile is as follows:
Insert image description here

Exchange the top element 7 and the end element 2 of the heap, adjust the remaining elements except 7 downwards to rebuild the large heap.
Insert image description here
At this time, 7 is already in order, exchange element 6 and element 3, and divide the elements 6 Adjust the remaining elements except 7 and 7 downwards to rebuild the big pile
Insert image description here
. At this time, 6 and 7 are already in order. Exchange element 5 and element 2. Adjust the remaining elements except 5, 6 and 7 downwards to rebuild the big pile. Heap
Insert image description here
At this time, 5, 6, and 7 are already in order. Exchange element 4 and element 2. At this time, the array is already in order. Insert image description here
After sorting, array a becomes
Insert image description here

useAdjust the algorithm upward to build a heapofAscending orderThe heap sort code is as follows:

#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
typedef int HPDataType;
//交换结点的函数
void Swap(HPDataType* p1, HPDataType* p2)
{
    
    
	HPDataType tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}
//向上调整算法(大堆)
void AdjustUp(HPDataType* a, int child)
{
    
    
	//找出双亲的下标
	int parent = (child - 1) / 2;

	while (child>0)
	{
    
    
		//孩子结点比双亲大则交换
		if (a[child] > a[parent])
		{
    
    
			Swap(&a[child], &a[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
    
    
			break;
		}
	}
}

//向下调整算法(大堆)
void AdjustDown(HPDataType* a, int n, int parent)
{
    
    
	//先默认左孩子是较大的
	int child = parent * 2 + 1;

	while (child < n)
	{
    
    
		//找出左右孩子中较大的
		if (child + 1 < n && a[child + 1] > a[child])
		{
    
    
			child++;
		}
		//孩子节点更小则交换
		if (a[child] > a[parent])
		{
    
    
			Swap(&a[child], &a[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
    
    
			break;
		}
	}
}
//排序
void HeapSort(int* a, int n)
{
    
    
	//向上调整建堆
	for (int i = 1; i < n; i++)
	{
    
    
		AdjustUp(a, i);
	}
	//最尾端数据下标为总数减一
	int end = n - 1;
	while (end > 0)
	{
    
    
		Swap(&a[0], &a[end]);
		//对剩余元素进行向下调整
		AdjustDown(a, end, 0);
		end--;
	}
}
int main()
{
    
    
	int a[] = {
    
     2,3,5,7,4,6 };
	HeapSort(a, sizeof(a) / sizeof(int));
	for (int i = 0; i < sizeof(a) / sizeof(int); i++)
	{
    
    
		printf("%d ", a[i]);
	}
	return 0;
}

The running results are as follows:
Insert image description here

Space complexity: O(1)
Average time complexity: O(nlogn)

3. Adjust the heap building sorting downwards

The difference between adjusting the heap building sort downwards and adjusting the heap building sort upwards is that the algorithms used when building the heap are different. The subsequent operations after building the heap are the same.

Still for the above case, we use the downward adjustment algorithm to build the heap
Insert image description here

Prerequisite for downward adjustment algorithm: the left and right subtrees must be heaps to adjust

Insert image description here

For this complete binary tree, the left subtree of its penultimate non-leaf node 2 is 4, and there is no right subtree. You can adjust it downward. You can also see that the left and right subtrees of the previous node 6 are single nodes. As a heap, we can start from the penultimate non-leaf node, which is the parent of the last node, and adjust downward:

Insert image description here

The subsequent operations after building the heap using downward adjustment are the same as the operations after building the heap through upward adjustment, so they will not be demonstrated here.

useAdjust the algorithm downward to build a heapofAscending orderThe heap sort code changes as follows:

void HeapSort(int* a, int n)
{
    
    
	向上调整建堆
	//for (int i = 1; i < n; i++)
	//{
    
    
	//	AdjustUp(a, i);
	//}
	// 
	//向下调整建堆
	for (int i = (n - 1 - 1) / 2; i >= 0; i--)
	{
    
    
		AdjustDown(a, n, i);
	}
	//最尾端数据下标为总数减一
	int end = n - 1;
	while (end > 0)
	{
    
    
		Swap(&a[0], &a[end]);
		//对剩余元素进行向下调整
		AdjustDown(a, end, 0);
		end--;
	}
}

Heap sort using downward adjustment to build heapTime complexity is: O(n), which is better than using upward adjustment to build a heap

4. Summary

To use heap sorting, you need to build a heap first. There are two ways to build a heap: upward adjustment algorithm and downward adjustment algorithm. However, the average time complexity of the downward adjustment algorithm is lower. After the heap is built, the head and tail data are swapped, and then the remaining The elements are rebuilt into the heap, and the ordered sequence can be obtained by repeated execution.

Summary of key knowledge:

  • Small heap: all parent nodes are smaller than the child nodes, and the root node is the smallest
  • Big pile: all parent nodes are larger than the child nodes, and the root node is the largest
  • Prerequisite for downward adjustment algorithm: the left and right subtrees must be heaps before they can be adjusted
  • Upward adjustment algorithm premise: the previous element is a heap
  • When building a heap in heap sorting: build a large heap in ascending order and a small heap in descending order.

Insert image description here

Guess you like

Origin blog.csdn.net/zcxyywd/article/details/132909533