Data structure-----heap (complete binary tree)

 Table of contents

Preface

pile

1. The concept of heap

2. Heap storage method

2. How to operate the heap

1. Structural representation of heap

2.Digital exchange interface function

3. Adjust upward (difficult point)

4. Adjust downward (difficult point)

5. Create a heap

 6. Insertion into the heap

 7. Judgment empty

8. Deletion of heap

 9. Get the root (top) element of the heap

10. Heap traversal

 11. Destroy the heap

Complete code

3. Application of heap (heap sort)

1. Algorithm introduction

2.Basic idea

3. Code implementation

4. Algorithm analysis


Preface

         Today we start to learn a kind of binary tree. Yes, it is a complete binary tree. A complete binary tree is also called a heap. Before that, we briefly introduced the concept of a complete binary tree (link: Data Structure-----Tree and Binary Tree Definition and Properties_Greytard's Blog-CSDN Blog ), what are the characteristics of this type of binary tree? How to implement the code? What are the applications? Let’s take a look below!

pile

1. The concept of heap

Heap is the collective name for a special type of data structure in computer science. The heap is usually an array object that can be viewed as a tree. It is an array at the physical level and a complete binary tree logically. A heap always satisfies the following properties:

  • The value of a node in the heap is always no greater than or no less than the value of its parent node;

  • The heap is always a complete binary tree.

  • A heap that satisfies any parent node being larger than its child nodes is called a big heap.

  • A heap that satisfies any child node that is larger than its parent node is called a small heap.

  • tip: (The creation of a large pile will be used as an example below)

as the picture shows:

 

2. Heap storage method

The storage principle of the heap is from top to bottom, from left to right, that is to say, there will be child nodes after the parent node above, and the left child node will be there first, so the heap can pass an array. It is expressed completely, as shown in the figure below:

2. How to operate the heap

The following are the basic functions to be implemented by a heap. I will explain them in detail one by one below.

void swap(DataType* a, DataType* b);//交换数据

void Adjust_Up(DataType* data, int child, int n);//向上调整

void Adjust_Down(DataType* data, int parent, int n);//向下调整

void Heap_Create(Heap* hp, DataType* data, int n);//创建堆

bool isEmpty(Heap* hp);//判断空

void Heap_Insert(Heap* hp, DataType x);//堆的插入

void Heap_Del(Heap* hp);//堆的删除操作

DataType Heap_Root(Heap* hp);//获取根元素

void Heap_show(Heap* hp);//堆的遍历

void Heap_Destory(Heap* hp);//堆的销毁

1. Structural representation of heap

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#define Maxsize 50

//顺序结构
//堆(完全二叉树)
typedef int DataType;	//定义数据的类型
typedef struct Heap
{
	int size;	//当前节点数量
	int capacity;	//最大容量
	DataType* data;	//数据储存地址
}Heap;

2.Digital exchange interface function

//数据交换接口
void swap(DataType* a, DataType* b) {
	DataType temp = *a;
	*a = *b;
	*b = temp;
}

3. Adjust upward (difficult point)

        When creating a large heap, the purpose of upward adjustment is to compare the size of the child node with the parent node if there is a child node. If the child node is larger than the parent node, then exchange it, and then the new child node will be the parent of the previous one. Nodes, the comparison continues in this way, and finally ends at the root node, as shown in the figure:

 Code:

//向上调整
void Adjust_Up(DataType* data, int child, int n) {
	int parent = (child - 1) / 2;
	while (child > 0) {
		//如果子节点大于父节点就进行数值交换,然后此时的子节点就是前一个父节点,再找到
		//新的父节点,继续进行同样的操作,直到根节点为止
		if (data[child] > data[parent])
		{
			swap(&data[child], &data[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}

4. Adjust downward (difficult point)

        The same is true for downward adjustment. If you have the current parent node position, you need to compare it with the child node. However, the child node has left and right child nodes, so the left and right child nodes also need to be compared to get the larger one. The child node is compared with the parent node. If the byte point is greater than the parent node, then the numbers are exchanged, and then the new parent node is the previous child node, and the same operation is performed in sequence.

Code: 

//向下调整
void Adjust_Down(DataType* data, int parent, int n) {
	int child = parent * 2 + 1;
	while (child <n ) {
		if (child+1 < n && data[child] < data[child+1])
		{
			//如果右子节点大于左子节点,那就child+1,选中到右子节点
			child++;
		}
		if (data[child] > data[parent]) {
			//同样的,有了当前父节点,然后找到子节点,进行向下遍历调整操作
			swap(&data[child], &data[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

5. Create a heap

There is already an array {5,1,2,3,6,4,8}. How to put this array into the heap? Similarly, space application applies for a continuous space, and then stores the data into this array in sequence, and finally adjusts it downward to achieve the heap form.

After being put into the heap, it is shown in the figure below: 

Code:

//创建堆
void Heap_Create(Heap* hp, DataType* data, int n) {
	assert(hp);
	hp->data = (DataType*)malloc(sizeof(DataType) * n);
	if (!hp->data) {
		printf("ERROR\n");
		exit(-1);
	}
	for (int i = 0; i < n; i++) {
		hp->data[i] = data[i];//赋值
	}
	hp->size = n;
	hp->capacity = Maxsize;
	for (int j = (n - 1) / 2; j >= 0; j--) {
		//创建完成了之后,就要进行向下调整
		Adjust_Down(hp->data, j ,hp->size);
	}
}

 6. Insertion into the heap

The insertion of the heap is to add an element at the end of the heap. After the addition is completed, the upward adjustment operation is performed, as shown in the following figure:

Code: 

//堆的插入
void Heap_Insert(Heap* hp, DataType x) {
	assert(hp);
	//如果此时的堆空间满了,那么就要去扩容空间
	if (hp->size == hp->capacity) {
		DataType* temp = (DataType*)realloc(hp->data,sizeof(DataType)  * (hp->capacity+1));//追加1个空间
		if (!temp) {
			printf("ERROR\n");
			exit(-1);
		}
		hp->data = temp;
		hp->data[hp->size] = x;
		hp->size++;
		hp->capacity++;
	}
	else
	{
		hp->data[hp->size] = x;
		hp->size++;
	}
	Adjust_Up(hp->data, hp->size - 1, hp->size);//插入后进行向上调整
}

 7. Judgment empty

//判断空
bool isEmpty(Heap* hp) {
	assert(hp);
	return hp->size == 0;
}

8. Deletion of heap

The deletion operation of the heap is to delete the root node. The process is to first exchange the last node with the root node, and then adjust downward again. ( In the heap deletion operation, the root node is deleted! )

Code: 

//堆的删除,删除根节点
void Heap_Del(Heap* hp) {
	assert(hp);
	if (!isEmpty(hp)) {
		swap(&hp->data[hp->size - 1], &hp->data[0]);//根节点和尾节点进行交换
		hp->size--;
		Adjust_Down(hp->data, 0, hp->size);//向下调整
	}
}

 9. Get the root (top) element of the heap

//获取堆顶元素
DataType Heap_Root(Heap* hp) {
	assert(hp);
	if (!isEmpty(hp))
		return hp->data[0];
	else
		exit(0);
}

10. Heap traversal

To traverse the heap, just follow the order of the array. Logically, a complete binary tree is traversed from top to bottom and from left to right. The code is as follows:

//输出堆元素(按照顺序)
void Heap_show(Heap* hp) {
	assert(hp);
	if (isEmpty(hp)) {
		printf("The Heap is etmpy\n");
		return;
	}
	for (int i = 0; i < hp->size; i++)
		printf("%d ", hp->data[i]);
}

 11. Destroy the heap

//堆的销毁
void Heap_Destory(Heap* hp) {
	assert(hp);
	hp->size = hp->capacity = 0;
	free(hp);//释放空间
}

Complete code

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#define Maxsize 50

//顺序结构
//堆(完全二叉树)
typedef int DataType;	//定义数据的类型
typedef struct Heap
{
	int size;	//当前节点数量
	int capacity;	//最大容量
	DataType* data;	//数据储存地址
}Heap;


//数据交换接口
void swap(DataType* a, DataType* b) {
	DataType temp = *a;
	*a = *b;
	*b = temp;
}

//向上调整
void Adjust_Up(DataType* data, int child, int n) {
	int parent = (child - 1) / 2;
	while (child > 0) {
		//如果子节点大于父节点就进行数值交换,然后此时的子节点就是前一个父节点,再找到
		//新的父节点,继续进行同样的操作,直到根节点为止
		if (data[child] > data[parent])
		{
			swap(&data[child], &data[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}

//向下调整
void Adjust_Down(DataType* data, int parent, int n) {
	int child = parent * 2 + 1;
	while (child <n ) {
		if (child+1 < n && data[child] < data[child+1])
		{
			//如果右子节点大于左子节点,那就child+1,选中到右子节点
			child++;
		}
		if (data[child] > data[parent]) {
			//同样的,有了当前父节点,然后找到子节点,进行向下遍历调整操作
			swap(&data[child], &data[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

//创建堆
void Heap_Create(Heap* hp, DataType* data, int n) {
	assert(hp);
	hp->data = (DataType*)malloc(sizeof(DataType) * n);
	if (!hp->data) {
		printf("ERROR\n");
		exit(-1);
	}
	for (int i = 0; i < n; i++) {
		hp->data[i] = data[i];//赋值
	}
	hp->size = n;
	hp->capacity = Maxsize;
	for (int j = (n - 1) / 2; j >= 0; j--) {
		//创建完成了之后,就要进行向下调整
		Adjust_Down(hp->data, j ,hp->size);
	}
}

//判断空
bool isEmpty(Heap* hp) {
	assert(hp);
	return hp->size == 0;
}

//堆的插入
void Heap_Insert(Heap* hp, DataType x) {
	assert(hp);
	//如果此时的堆空间满了,那么就要去扩容空间
	if (hp->size == hp->capacity) {
		DataType* temp = (DataType*)realloc(hp->data,sizeof(DataType)  * (hp->capacity+1));//追加1个空间
		if (!temp) {
			printf("ERROR\n");
			exit(-1);
		}
		hp->data = temp;
		hp->data[hp->size] = x;
		hp->size++;
		hp->capacity++;
	}
	else
	{
		hp->data[hp->size] = x;
		hp->size++;
	}
	Adjust_Up(hp->data, hp->size - 1, hp->size);//插入后进行向上调整
}

//堆的删除,取出根节点
void Heap_Del(Heap* hp) {
	assert(hp);
	if (!isEmpty(hp)) {
		swap(&hp->data[hp->size - 1], &hp->data[0]);//根节点和尾节点进行交换
		hp->size--;
		Adjust_Down(hp->data, 0, hp->size);//向下调整
	}
}


//获取堆顶元素
DataType Heap_Root(Heap* hp) {
	assert(hp);
	if (!isEmpty(hp))
		return hp->data[0];
	else
		exit(0);
}

//输出堆元素(按照顺序)
void Heap_show(Heap* hp) {
	assert(hp);
	if (isEmpty(hp)) {
		printf("The Heap is etmpy\n");
		return;
	}
	for (int i = 0; i < hp->size; i++)
		printf("%d ", hp->data[i]);
}

//堆的销毁
void Heap_Destory(Heap* hp) {
	assert(hp);
	hp->size = hp->capacity = 0;
	free(hp);//释放空间
}

3. Application of heap (heap sort)

1. Algorithm introduction

        Heapsort refers to a sorting algorithm designed using the data structure of a heap. Stacking is a structure that approximates a complete binary tree and satisfies the properties of stacking: that is, the key value or index of a child node is always smaller (or larger) than its parent node.

2.Basic idea

Taking advantage of the feature that the top record of the big top heap (small top heap) is the maximum key (minimum key), it becomes simple to select the maximum record (minimum record) from the disorder every time.

① Construct the sequence to be sorted into a maximum heap. At this time, the maximum value of the sequence is the root node.
② Exchange the root node with the last element of the sequence to be sorted.
③ Then maintain the previous node from the root node to the element as the maximum. Heap, and so on, finally get an increasing sequence

3. Code implementation

#include<stdio.h>
#include<assert.h>
//数据交换接口
void swap(int *a, int *b) {
	int temp = *a;
	*a = *b;
	*b = temp;
}

//向下调整
void Adjust_Down(int* data, int parent, int n) {
	int child = parent * 2 + 1;
	while (child < n) {
		if (child + 1 < n && data[child] < data[child + 1])
		{
			//如果右子节点大于左子节点,那就child+1,选中到右子节点
			child++;
		}
		if (data[child] > data[parent]) {
			//同样的,有了当前父节点,然后找到子节点,进行向下遍历调整操作
			swap(&data[child], &data[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

//堆排序算法
void Heap_sort(int* arr, int n) {
	assert(arr);
	for (int i = (n - 2) / 2; i >= 0; i--) {
		Adjust_Down(arr, i, n);
	}//先形成最大堆

	int end = n - 1;
	//从小到大排序
	while (end > 0) {
		swap(&arr[0], &arr[end]);
		Adjust_Down(arr, 0, end);
		end--;	//此时最后一个也就是当前的最大值已经排序好了
	}
}

int main() {
	int a[9] = { 5,1,2,3,6,4,8,2,10 };
	Heap_sort(a, sizeof(a) / sizeof(int));
	for (int i = 0; i < sizeof(a) / sizeof(int); i++) {
		printf("%d ", a[i]);
	}
}
//输出
//1 2 2 3 4 5 6 8 10

4. Algorithm analysis

  • Average time complexity: O(nlogn)
  • Optimal time complexity: O(nlogn)
  • Worst time complexity: O(nlogn)
  • Stability: Unstable

 That’s it for this issue, see you next time!

 Share a wallpaper:

Guess you like

Origin blog.csdn.net/m0_73633088/article/details/133203358