[Data structure -- C language] Heap, you are a heap, see how I can handle you thoroughly

Table of contents

1. The concept and structure of the heap

1.1 Concepts (concepts are always important)

1.2 Structure, divided into two types

1.2.1 Small heap/small root heap example

1.2.2 Big heap/big root heap example

2. Heap interface

3. Interface implementation

3.1 Heap initialization

3.2 Destruction of the heap

3.3 Heap insertion

Functional Analysis:

Function realization:

3.4 Heap deletion

Functional Analysis:

Function realization:

3.5 Get the data at the top of the heap

3.6 The number of data in the heap

3.7 Heap Empty Judgment

4. Complete code


1. The concept and structure of the heap

1.1 Concepts (concepts are always important)

The above paragraph is the concept of piles, but this is too boring, let’s talk about it in a simple way, knocking on the blackboard:

The essence of the heap is a complete binary tree.

Big heap (also called big root heap): the parent node is greater than/equal to the child node.

Small pair (also called small root heap): the parent node is less than/equal to the child node.

If the above conditions are not met, then it is not a heap.

Properties of the heap :

1. The value of a node in the heap is always not greater than or not less than the value of its parent node;
2. The heap is always a complete binary tree.

1.2 Structure, divided into two types

1.2.1 Small heap/small root heap example

1.2.2 Big heap/big root heap example

Let's look at a topic:

The following sequence of keywords is a heap: (A)

A 100,60,70,50,32,65

B 60,70,65,50,32,100

C 65,100,70,32,50,60

D 70,65,100,32,50,60

E 32,50,100,70,65,60

F 50,100,70,65,60,32

Analysis : We draw a graph to analyze

2. Heap interface

This article is implemented using the small heap as an example. The data storage of the heap is stored in an array, and the storage structure of the data in memory is stored sequentially. We understand it in a logical structure for easy understanding.

The interfaces of the heap include: initialization, destruction, insertion, deletion, taking the top of the heap, the number of data in the heap, and empty judgment.

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>

typedef int HPDataType;
typedef struct Heap
{
	HPDataType* a;
	int size;
	int capacity;
}Heap;

// 堆的初始化
void HeapInit(Heap* hp);
// 堆的销毁
void HeapDestory(Heap* hp);
//交换
void Swap(HPDataType* p1, HPDataType* p2);
//向上调整
void AdjustUp(HPDataType* a, int child);
//向下调整
void AdjustDown(HPDataType* a, int size, int parent);
// 堆的插入
void HeapPush(Heap* hp, HPDataType x);
// 堆的删除
void HeapPop(Heap* hp);
// 取堆顶的数据
HPDataType HeapTop(Heap* hp);
// 堆的数据个数
int HeapSize(Heap* hp);
// 堆的判空
bool HeapEmpty(Heap* hp);

3. Interface implementation

Many of our interfaces are similar to the previous data structure articles. They have been explained many times before, so I won’t explain them here. If there is something you don’t understand, you can refer to the previous data structure articles.

3.1 Heap initialization

void HeapInit(Heap* hp)
{
	assert(hp);

	hp->a = NULL;
	hp->size = 0;
	hp->capacity = 0;
}

3.2 Destruction of the heap

void HeapDestory(Heap* hp)
{
	assert(hp);

	free(hp->a);
	hp->a = NULL;
	hp->size = hp->capacity = 0;
}

3.3 Heap insertion

Heap insertion is more complicated and difficult. Let's analyze it first, and then implement the function.

Functional Analysis:

1. When inserting, we first need to check whether the array needs to be expanded, first determine whether it is full, if the space is full, expand the capacity first, and then insert the new element at the end of the array;

2. When we insert a new element, we need to analyze whether the heap satisfies the structure of the small heap. If not, we need to adjust the new element upwards.

3. Upward adjustment process analysis:

Let's take an example to analyze: If the structure of the heap is destroyed after inserting an element into a small heap, how to adjust to restore the structure of the small heap.

a. When we find that after inserting a 10 into the small heap, 10 is smaller than the parent node 28, which destroys the structure of the small heap, and we need to adjust the heap;

b. The physical structure of the heap is an array, so we can find the parent node through the subscript. Here is the formula for finding the parent node: parent = (child-1)/2. When we find the parent node, compare the child node with the parent node. If it is smaller than the parent node, we exchange the elements of the two nodes. The exchanged parent node and its parent node may not satisfy the small heap, so we need to continue upward adjustment of

c. Loop to compare and adjust, when child = 0, our adjustment is over, so our loop judgment condition is child > 0.

Note: After one adjustment, our heap has become a small heap, and we will jump out of the loop.

Let's draw a picture according to the above ideas:

Our analysis of the function is over, and we start to realize the function.

Function realization:

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;
		}
	}
}

//log N 
void HeapPush(Heap* hp, HPDataType x)
{
	assert(hp);

	if (hp->size == hp->capacity)
	{
		int newcapacity = hp->capacity == 0 ? 4 : 2 * hp->capacity;
		HPDataType* tmp = (HPDataType*)realloc(hp->a, sizeof(HPDataType) * newcapacity);
		if (NULL == tmp)
		{
			perror("realloc fail:");
		}

		hp->a = tmp;
		hp->capacity = newcapacity;
	}
	hp->a[hp->size] = x;
	hp->size++;

	AdjustUp(hp->a, hp->size - 1);
}

We will reuse the exchange and upward adjustment later, so we encapsulate the two functions into a function.

3.4 Heap deletion

The deletion of the heap is to delete the element at the top of the heap.

Idea: Exchange the top data with the last data, delete the last data, and then adjust from the top of the heap.

Functional Analysis:

When we delete the data at the top of the heap, we cannot delete it directly. Deleting the data at the top of the heap directly will destroy the heap structure, and the time complexity of building the heap is too high, so it is not recommended. Here we introduce a method with a lower complexity:

1. We exchange the top data with the last data first, then delete the last data, and finally adjust downward from the top of the heap;

2. The downward adjustment is more complicated. Let’s analyze and draw a picture to explain:

a. At this time, our parent node is the top node of the heap. Next, we need to find the smaller of the two child nodes as the child node. The formula for finding the child node here is: child = parent*2 + 1;

b. If the child is smaller than the father, exchange it, and continue to adjust downwards, let the parent go to the child position, and then calculate the child position;

c. When the subscript of the child is greater than the size of the array, the loop ends and the entire adjustment is completed.

Note: After one adjustment, our heap has become a small heap, and we will jump out of the loop.

Function realization:

void AdjustDown(HPDataType* a, int size, int parent)
{
	int child = parent * 2 + 1;
	while (child < size)//当child大于了数组大小就跳出循环
	{
		//找出左右孩子中小/大的那个(假设法)
		if (child + 1 < size && a[child + 1] < a[child])
		{
			child++;
		}

		if (a[child] < a[parent])
		{
			Swap(&a[parent], &a[child]);

			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

//log N
void HeapPop(Heap* hp)
{
	assert(hp);
	assert(!HeapEmpty(hp));

	Swap(&hp->a[0], &hp->a[hp->size - 1]);
	hp->size--;

	AdjustDown(hp->a, hp->size, 0);
}

3.5 Get the data at the top of the heap

HPDataType HeapTop(Heap* hp)
{
	assert(hp);
	assert(!HeapEmpty(hp));

	return hp->a[0];
}

3.6 The number of data in the heap

int HeapSize(Heap* hp)
{
	assert(hp);
	assert(!HeapEmpty(hp));

	return hp->size;
}

3.7 Heap Empty Judgment

bool HeapEmpty(Heap* hp)
{
	assert(hp);

	return hp->size == 0;
}

4. Complete code

The complete code is in the code warehouse: Heap Xiaobai is working hard on jy/DataStructure - Code Cloud - Open Source China (gitee.com)

Guess you like

Origin blog.csdn.net/Ljy_cx_21_4_3/article/details/130903751