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

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

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;
} 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,&hp->a[hp->size-1]);
//Delete the last element, which is the element we want to delete
hp->size--;
}

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);
//Heap insert function
extern void HeapPush(HP* hp,HPDataType x);
//Heap print function
extern void HeapPrint(HP* hp);
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;
}

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
}
//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;
}
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,&hp->a[hp->size-1]);
//Delete the last element, which is the element we want to delete
hp->size--;
}

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); i++)
{
HeapPush(&hp, a[i]);
}
HeapPrint(&hp);
HeapPop(&hp);
HeapPrint(&hp);
HeapDestroy(&hp);
}

int main()
{
test();
return 0;
}

Posted on Mon, 08 Nov 2021 19:14:56 -0500 by dspeer