Structure des données : implémentation du tas (implémentation C)

insérez la description de l'image ici

Page d'accueil personnelle : Page d'accueil personnelle
Colonne personnelle : "Structure des données" "Langage C"


pile

Lorsqu’un arbre binaire complet est stocké sous forme de liste séquentielle, on l’appelle un tas.

  • Le tas est toujours un arbre binaire complet
  • La valeur d'un nœud du tas n'est toujours pas supérieure (grand tas) ou pas inférieure (petit tas) à la valeur de son nœud parent

Il peut être utilisé pour résoudre les principaux problèmes ou trier les tas
insérez la description de l'image ici

Voici la fonction du tas à implémenter, l'accent étant mis sur l'insertion et la suppression du tas.


//堆的构建
void HeapInit(Heap* hp);

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

//堆的插入
void HeapPush(Heap* hp, HPDataType x);

//堆的删除
void HeapPop(Heap* hp);

//取堆顶的数据
HPDataType HeapTop(Heap* hp);

//堆的数据个数
int HeapSize(Heap* hp);

//堆的判空
bool HeapEmpty(Heap* hp);

2. Idées de mise en œuvre

Les diagrammes de la partie suivante sont tous basés sur une structure logique ! ! !
Ce qui est construit ici est un petit tas.

1. Définition de la structure

Un tas utilise une table de séquence pour stocker un arbre binaire complet, la structure du tas est donc la même que celle de la table de séquence.
Un pointeur vers l'espace ouvert dynamiquement (données), une variable pour enregistrer la taille de l'espace (capacité) et une variable pour enregistrer les données effectives dans l'espace (taille).

typedef int HPDataType;

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

2. Construction du tas (HeapInit)

Malloc un morceau d'espace, utilisez les données pour enregistrer son adresse, la capacité d'enregistrer la taille de l'espace à ce moment et définissez la taille sur 0 (il n'y a aucune donnée valide dans l'espace à ce moment).

//堆的构建
#define SIZE 4

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

	hp->data = (HPDataType*)malloc(sizeof(HPDataType) * SIZE);
	if (hp == NULL) 
	{
    
    
		perror("mallo: ");
		exit(-1);
	}

	hp->capacity = SIZE;
	hp->size = 0;
}

3. Destruction du tas (HeapDestroy)

Libérez l'espace ouvert dynamiquement et définissez la capacité et la taille sur 0 (à ce stade, la taille de l'espace est 0)

//堆的销毁
void HeapDestroy(Heap* hp)
{
    
    
	assert(hp);

	free(hp->data);
	hp->data = NULL;

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

4. Insertion de tas (HeapPush)

Insérez les données à la fin du tas (après le dernier nœud enfant), puis comparez-les avec son nœud parent. Si le nœud est plus petit que son nœud parent (voici un petit tas), échangez les valeurs​​​ des deux nœuds jusqu'à ce que le nœud soit en haut du tas ou que son nœud parent soit plus petit que ce nœud.

  • Supposons que l'indice du nœud soit i, alors l'indice de son nœud parent est ( i - 1 ) / 2

insérez la description de l'image ici

//交换
void swap(HPDataType* a, HPDataType* b)
{
    
    
	HPDataType tmp = *a;
	*a = *b;
	*b = tmp;
}

//向上调整 假设该节点是 i,父节点是 (i - 1) / 2
void AdjustUp(HPDataType* data, int child)
{
    
    
	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 HeapPush(Heap* hp, HPDataType x)
{
    
    
	assert(hp);

	//检查容量
	if (hp->capacity == hp->size)
	{
    
    
		HPDataType* tmp = (HPDataType*)realloc(hp->data ,sizeof(HPDataType) * (hp->capacity * 2));
		if (tmp == NULL)
		{
    
    
			perror("realloc:");
			exit(-1);
		}

		hp->data = tmp;
		hp->capacity *= 2;
	}

	hp->data[hp->size] = x;
	hp->size++;

	//向上调整   传入数组和出入数据的下标
	//此处是小堆
	AdjustUp(hp->data, hp->size - 1);
}

5. Suppression du tas (HeapPop)

La suppression du tas consiste à supprimer les données supérieures du tas.
Les données en haut du tas sont échangées avec les données à la fin du tas, la taille est réduite de un, puis les nouvelles données du haut sont comparées à la valeur minimale des nœuds enfants gauche et droit. les données supérieures sont supérieures à la valeur minimale des nœuds enfants gauche et droit, les données sont échangées et la nouvelle valeur minimale des nœuds enfants gauche et droit
est comparée. Jusqu'à ce que les données soient inférieures à la valeur minimale des enfants gauche et droit, ou que les données dépassent la plage de données valide.

  • Supposons que l'indice d'un nœud soit i, l'indice de son nœud enfant gauche : i * 2 + 1, l'indice de son enfant droit : i * 2 + 2
  • Supprimez les données en haut du tas et ne pouvez pas accéder aux données pour écraser les données en haut du tas. Si les données sont déplacées, les nœuds frères peuvent devenir des nœuds parent-enfant et la relation de taille entre les nœuds frères n'est pas garantie, ce qui peut détruire la structure du tas (ici, la petite structure du tas sera détruite).

insérez la description de l'image ici

//交换
void swap(HPDataType* a, HPDataType* b)
{
    
    
	HPDataType tmp = *a;
	*a = *b;
	*b = tmp;
}


//向下调整,假设该节点是 i, 右孩子节点是 2 * i + 1,左孩子节点是 2 * i + 2
void AdjustDown(HPDataType* data, int parent, int size)
{
    
    
	int child = parent * 2 + 1;

	while (parent < size)
	{
    
    
		//防止越界                    找左右孩子中最小的
		if (child + 1 < size && data[child] > data[child + 1])
		{
    
    
			child++;
		}

		if (child < size && data[parent] > data[child])
		{
    
    
			swap(&data[parent], &data[child]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
    
    
			break;
		}
	}
}



//堆的删除  首元素 与 尾元素交换,新的堆顶在向下调整
void HeapPop(Heap* hp)
{
    
    
	assert(hp);
	assert(!HeapEmpty(hp));
	
	hp->data[0] = hp->data[hp->size - 1];
	hp->size--;

	//向下调整
	AdjustDown(hp->data, 0, hp->size);
}

6. Récupérez les données en haut du tas (HeapTop)

Lisez simplement l'indice de l'espace du tableau comme 0.

//取堆顶的数据
HPDataType HeapTop(Heap* hp)
{
    
    
	assert(hp);

	return hp->data[0];
}

7. Le nombre de données dans le tas (HeapSize)

La taille dans la structure du tas indique le nombre de données valides dans le tas à ce moment-là, accédez simplement à la taille.

//堆的数据个数
int HeapSize(Heap* hp)
{
    
    
	assert(hp);

	return hp->size;
}

8. Tas de jugement vide (HeapEmpty)

size indique le nombre de données valides dans le tas, si size == 0, cela signifie que le tas est vide.

//堆的判空
bool HeapEmpty(Heap* hp)
{
    
    
	assert(hp);

	return hp->size == 0;
}

3. Mise en œuvre du code

//Heap.c   文件


#include "Heap.h"


//堆的构建
void HeapInit(Heap* hp)
{
    
    
	assert(hp);

	hp->data = (HPDataType*)malloc(sizeof(HPDataType) * SIZE);
	if (hp == NULL) 
	{
    
    
		perror("mallo: ");
		exit(-1);
	}

	hp->capacity = SIZE;
	hp->size = 0;
}


//堆的销毁
void HeapDestroy(Heap* hp)
{
    
    
	assert(hp);

	free(hp->data);
	hp->data = NULL;

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

//交换
void swap(HPDataType* a, HPDataType* b)
{
    
    
	HPDataType tmp = *a;
	*a = *b;
	*b = tmp;
}

//向上调整 假设该节点是 i,父节点是 (i - 1) / 2
void AdjustUp(HPDataType* data, int child)
{
    
    
	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 HeapPush(Heap* hp, HPDataType x)
{
    
    
	assert(hp);

	//检查容量
	if (hp->capacity == hp->size)
	{
    
    
		HPDataType* tmp = (HPDataType*)realloc(hp->data ,sizeof(HPDataType) * (hp->capacity * 2));
		if (tmp == NULL)
		{
    
    
			perror("realloc:");
			exit(-1);
		}

		hp->data = tmp;
		hp->capacity *= 2;
	}

	hp->data[hp->size] = x;
	hp->size++;

	//向上调整   传入数组和出入数据的下标
	//此处是小堆
	AdjustUp(hp->data, hp->size - 1);
}



//向下调整,假设该节点是 i, 右孩子节点是 2 * i + 1,左孩子节点是 2 * i + 2
void AdjustDown(HPDataType* data, int parent, int size)
{
    
    
	int child = parent * 2 + 1;

	while (parent < size)
	{
    
    
		//防止越界                    找左右孩子中最小的
		if (child + 1 < size && data[child] > data[child + 1])
		{
    
    
			child++;
		}

		if (child < size && data[parent] > data[child])
		{
    
    
			swap(&data[parent], &data[child]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
    
    
			break;
		}
	}
}



//堆的删除  首元素 与 尾元素交换,新的堆顶在向下调整
void HeapPop(Heap* hp)
{
    
    
	assert(hp);
	assert(!HeapEmpty(hp));
	
	hp->data[0] = hp->data[hp->size - 1];
	hp->size--;

	//向下调整
	AdjustDown(hp->data, 0, hp->size);
}



//取堆顶的数据
HPDataType HeapTop(Heap* hp)
{
    
    
	assert(hp);

	return hp->data[0];
}




//堆的数据个数
int HeapSize(Heap* hp)
{
    
    
	assert(hp);

	return hp->size;
}



//堆的判空
bool HeapEmpty(Heap* hp)
{
    
    
	assert(hp);

	return hp->size == 0;
}
//Heap.h  文件

#pragma once

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

#define SIZE 4

typedef int HPDataType;

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


//堆的构建
void HeapInit(Heap* hp);

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

//堆的插入
void HeapPush(Heap* hp, HPDataType x);

//堆的删除
void HeapPop(Heap* hp);

//取堆顶的数据
HPDataType HeapTop(Heap* hp);

//堆的数据个数
int HeapSize(Heap* hp);

//堆的判空
bool HeapEmpty(Heap* hp);


Résumer

Ce qui précède est mon implémentation du tas ! ! !
insérez la description de l'image ici

Je suppose que tu aimes

Origine blog.csdn.net/li209779/article/details/132227139
conseillé
Classement