heap
The heap in the data structure is different from the heap in the operating system (the heap in the operating system is used to store dynamic memory). The heap in the data structure is the storage mode of data. The heap in the data structure is a complete binary tree
Since the heap is stored in the form of a complete binary tree, it is very suitable to represent it in the form of an array
Concept and structure of reactor
If there is a key set K = {k0, k1, k2,..., kn-1}, all its elements are stored in a one-dimensional array in the order of complete binary tree, and meet the following requirements: ki < = k2i + 1 and Ki < = k2i + 2 (KI > = k2i + 1 and Ki > = k2i + 2) I = 0, 1, 2..., it is called small heap (or large heap). The heap with the largest root node is called the maximum heap or large root heap, and the heap with the smallest root node is called the minimum heap or small root heap.
Pile: in a tree and subtree, any father is greater than or equal to the child
Small pile: in a tree and subtree, any father is less than or equal to the child
Nature of heap
The value of a node in the heap is always not greater than or less than the value of its parent node;
Heap is always a complete binary tree**
Heap structure (implemented here)
Since it is still an array structure, it is still the processing method of sequential table, array pointer, size and capacity. Although we physically represent it in the form of sequential table, the data it actually represents is a complete binary tree.
Structure of reactor
typedef int HPDataType; typedef struct Heap { HPDataType* a; int size; int capacity; }HP;
Heap initialization function HeapInit
It is an array pointing to NULL, and both size and capacity are zero
//Heap initialization function void HeapInit(HP* hp) { assert(hp); hp->a = NULL; hp->size = hp->capacity = 0; }
Heap destroy function HeapDestroy
Because the array is opened dynamically, it needs to be destroyed after use, otherwise it will leak memory
//Heap destroy function void HeapDestroy(HP* hp) { assert(hp); free(hp->a); hp->size = hp->capacity = 0; }
Heap print function HeapPrint
It can be imagined as a kind of fast debugging, which is similar to serial port printing in single chip microcomputer to see the data sending and receiving
//Heap print function void HeapPrint(HP* hp) { int i = 0; for (i = 0; i < hp->size; i++) { printf("%d ", hp->a[i]); } printf("\n"); }
Adjust function up
In order not to affect the storage form of data (a lot of data has to be a lot of data), the inserted data can not destroy the form of a lot of data. We need to adjust and peel off the data in the heap insertion function
We can see that the inserted data has no impact on other nodes, but only the nodes from this node to the root path. How to solve the impact on this path? We can visually see that it is only upward adjustment on this path
Find the parent node through parent = (child-1) / 2 and compare it with it. Then the father will exchange positions (a lot) when he is young. After the exchange, he will find the parent node above until he finds that the father is greater than the child, so he will not exchange
//Adjust function up void AdjustUp(HPDataType* a, int child) { assert(a); int parent = (child - 1) / 2; while (child>0) { if (a[parent] < a[child])//A father exchanges when he is younger than a child (a lot) { a[parent] = a[parent] ^ a[child]; a[child] = a[parent] ^ a[child]; a[parent] = a[parent] ^ a[child]; //After the exchange, call the child and father again child = parent; parent = (child - 1) / 2; } else { break; } } }
Heap insert function HeapPush
//Heap insertion function (to keep the original form, large heap or large heap, small heap or small heap) void HeapPush(HP* hp, HPDataType x) { assert(hp); //Judge expansion if (hp->size == hp->capacity) { //Capacity to new capacity int newcapacity = hp->capacity == 0 ? 4 : hp->capacity * 2; //Capacity expansion HPDataType* tmp = (HPDataType*)realloc(hp->a, sizeof(HPDataType) * newcapacity); //Capacity increase failed if (!tmp) { printf("realloc fail\n"); exit(-1); } //Successful capacity increase hp->a = tmp; hp->capacity = newcapacity; } //Release data hp->a[hp->size] = x; hp->size++; //Realize a lot //The upward adjustment of this part can also be used in other places to peel it off AdjustUp(hp->a, hp->size - 1);//child subscript }
Determine whether the heap is empty function HeapErmpy
//Determine whether the heap is an empty function bool HeapErmpy(HP* hp) { assert(hp); return hp->size == 0; }
Return heap size function HeapSize
//Return heap size function int HeapSize(HP* hp) { assert(hp); return hp->size; }
The exchange function is also used below, so we might as well peel it out and encapsulate it, so there is no need to write it again
Swap function swap
//Exchange function void Swap(HPDataType* px, HPDataType* py) { *px = *px ^ *py; *py = *px ^ *py; *px = *px ^ *py; }
Downward adjustment function AdjustDown
//Downward adjustment function void AdjustDown(HPDataType* a, int size, int parent) { assert(a); //Create a child variable and add 1 to it for two children int child = parent * 2 + 1; while (child< size) { //Choose older children if (child + 1 < size && a[child] < a[child + 1]) { child++; } //Older children exchange when they are older than their father if (a[child] > a[parent]) { Swap(&a[child], &a[parent]); parent = child; child = parent * 2 + 1; } } }
Heap delete function HeapPop
We can think that after the hypothetical root is exchanged with the last element of the heap, delete the last element, and then operate the heap. You will find that we have not destroyed the original overall structure
//Heap delete function (delete the data at the top of the heap, that is, take the maximum value) //It's impossible to delete all the time, so we need a space judgment function void HeapPop(HP* hp) { assert(hp); assert(!HeapErmpy(hp)); //The root and the last element of the heap are exchanged Swap(&hp->a[0],&hp->a[hp->size-1]); //Delete the last element, which is the element we want to delete hp->size--; //Downward adjustment AdjustDown(hp->a,hp->size,0); }
code
Heap.h
#pragma once #include<stdio.h> #include<stdlib.h> #include<assert.h> #include<stdbool.h> typedef int HPDataType; typedef struct Heap { HPDataType* a; int size; int capacity; }HP; //Heap initialization function extern void HeapInit(HP* hp); //Heap destroy function extern void HeapDestroy(HP* hp); //Adjust function up extern void AdjustUp(HPDataType* a,int child); //Heap insert function extern void HeapPush(HP* hp,HPDataType x); //Heap print function extern void HeapPrint(HP* hp); //Downward adjustment function extern void AdjustDown(HPDataType* a, int size, int parent); //Heap delete function extern void HeapPop(HP* hp); //Determine whether the heap is an empty function extern bool HeapErmpy(HP* hp); //Exchange function extern void Swap(HPDataType* px, HPDataType* py); //Return heap size function extern int HeapSize(HP* hp);
Heap.c
#define _CRT_SECURE_NO_WARNINGS 1 #include"Heap.h" //Heap initialization function void HeapInit(HP* hp) { assert(hp); hp->a = NULL; hp->size = hp->capacity = 0; } //Heap destroy function void HeapDestroy(HP* hp) { assert(hp); free(hp->a); hp->size = hp->capacity = 0; } //Adjust function up void AdjustUp(HPDataType* a, int size, int child) { assert(a); int parent = (child - 1) / 2; while (child>0) { if (a[parent] < a[child])//A father exchanges when he is younger than a child (a lot) { Swap(&a[parent], &a[child]); //After the exchange, call the child and father again child = parent; parent = (child - 1) / 2; } else { break; } } } //Heap insertion function (to keep the original form, large heap or large heap, small heap or small heap) void HeapPush(HP* hp, HPDataType x) { assert(hp); //Judge expansion if (hp->size == hp->capacity) { //Capacity to new capacity int newcapacity = hp->capacity == 0 ? 4 : hp->capacity * 2; //Capacity expansion HPDataType* tmp = (HPDataType*)realloc(hp->a, sizeof(HPDataType) * newcapacity); //Capacity increase failed if (!tmp) { printf("realloc fail\n"); exit(-1); } //Successful capacity increase hp->a = tmp; hp->capacity = newcapacity; } //Release data hp->a[hp->size] = x; hp->size++; //Realize a lot //The upward adjustment of this part can also be used in other places to peel it off //Adjust the data form of the heap upward so that it is still in the form of a pile AdjustUp(hp->a, hp->size, hp->size - 1); } //Heap print function void HeapPrint(HP* hp) { assert(hp); int i = 0; for (i = 0; i < hp->size; i++) { printf("%d ", hp->a[i]); } printf("\n"); } //Determine whether the heap is an empty function bool HeapErmpy(HP* hp) { assert(hp); return hp->size == 0; } //Return heap size function int HeapSize(HP* hp) { assert(hp); return hp->size; } //Exchange function void Swap(HPDataType* px, HPDataType* py) { *px = *px ^ *py; *py = *px ^ *py; *px = *px ^ *py; } //Downward adjustment function void AdjustDown(HPDataType* a, int size, int parent) { assert(a); //Create a child variable and add 1 to it for two children int child = parent * 2 + 1; while (child< size) { //Choose older children if (child + 1 < size && a[child] < a[child + 1]) { child++; } //Older children exchange when they are older than their father if (a[child] > a[parent]) { Swap(&a[child], &a[parent]); parent = child; child = parent * 2 + 1; } else { break; } } } //Heap delete function (delete the data at the top of the heap, that is, take the maximum value) //It's impossible to delete all the time, so we need a space judgment function void HeapPop(HP* hp) { assert(hp); assert(!HeapErmpy(hp)); //The root and the last element of the heap are exchanged Swap(&hp->a[0],&hp->a[hp->size-1]); //Delete the last element, which is the element we want to delete hp->size--; //Downward adjustment AdjustDown(hp->a,hp->size,0); }
test.c
#define _CRT_SECURE_NO_WARNINGS 1 #include"Heap.h" void test() { int a[] = { 70,56,30,25,15,75 }; HP hp; HeapInit(&hp); int i = 0; for (i = 0; i < sizeof(a) / sizeof(a[0]); i++) { HeapPush(&hp, a[i]); } HeapPrint(&hp); HeapPop(&hp); HeapPrint(&hp); HeapDestroy(&hp); } int main() { test(); return 0; }