データ構造:ヒープ実装(C実装)

ここに画像の説明を挿入

個人ホームページ:個人ホームページ
個人コラム:「データ構造」 「C言語」


パイル

完全なバイナリ ツリーが順次リストとして格納される場合、それはヒープと呼ばれます。

  • ヒープは常に完全なバイナリ ツリーです
  • ヒープのノードの値は常にその親ノードの値より大きくない (大きなヒープ) か、それより小さくない (小さなヒープ)

上位 k 個の問題やヒープ ソートの解決に使用できます
ここに画像の説明を挿入

以下にヒープの挿入削除を中心に実装するヒープの機能を示します。


//堆的构建
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. 実装アイデア

次のパートの図はすべて論理構造に基づいています。
ここに構築されているのは小さな山です。

1. 構造の定義

ヒープはシーケンス テーブルを使用して完全なバイナリ ツリーを格納するため、ヒープの構造はシーケンス テーブルの構造と同じです。
動的に開かれる空間へのポインタ(データ)、空間のサイズ(容量)を記録する変数、空間内の有効なデータを記録する変数(サイズ)。

typedef int HPDataType;

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

2. ヒープ構築(HeapInit)

スペースの一部を割り当て、そのアドレスを記録するためにデータを使用し、現時点でスペースのサイズを記録するために容量を使用し、サイズを 0 に設定します (現時点ではスペースに有効なデータがありません)。

//堆的构建
#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. ヒープ破壊(HeapDestroy)

動的に開いたスペースを解放し、容量とサイズを0に設定します(このとき、スペースのサイズは0です)

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

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

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

4. ヒープ挿入(HeapPush)

ヒープの最後 (最後の子ノードの後) にデータを挿入し、その親ノードと比較します。ノードが親ノードより小さい場合 (ここでは小さなヒープです)、値を交換します。ノードがヒープの最上位になるか、その親ノードがこのノードより小さくなるまで、2 つのノードのうちの 1 つを繰り返します。

  • ノードの添字が i であるとすると、その親ノードの添字は ( i - 1 ) / 2 となります。

ここに画像の説明を挿入

//交换
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. ヒープ削除(HeapPop)

ヒープ削除とは、ヒープの先頭データを削除することです。
ヒープの先頭のデータとヒープの末尾のデータを交換し、サイズを 1 つ減らしてから、新しい先頭のデータと左右の子ノードの最小値を比較します。先頭のデータが左右の子ノードの最小値より大きい場合、データが交換され、新しい左右の子ノードの最小値が
比較されます。データが左右の子の最小値未満になるまで、またはデータが有効なデータ範囲を超えるまで。

  • ノードの添字が i であるとします。その左の子ノードの添字: i * 2 + 1、その右の子の添字: i * 2 + 2
  • ヒープの先頭にあるデータを削除し、そのデータに移動してヒープの先頭にあるデータを上書きすることはできません。データを移動すると、兄弟ノードが親子ノードになる可能性があり、兄弟ノード間のサイズ関係が保証されず、ヒープ構造が破壊される可能性があります(ここでは小さいヒープ構造が破壊されます)。

ここに画像の説明を挿入

//交换
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. ヒープの先頭にあるデータを取得します (HeapTop)

配列空間の添字を 0 として読み取るだけです。

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

	return hp->data[0];
}

7. ヒープ内のデータ数 (HeapSize)

ヒープ構造内のサイズは、その時点でヒープ内に有効なデータの数を示します。サイズにアクセスするだけです。

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

	return hp->size;
}

8. ヒープ空判定(HeapEmpty)

size はヒープ内の有効なデータの数を示します。size == 0 の場合、ヒープが空であることを意味します。

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

	return hp->size == 0;
}

3. コードの実装

//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);


要約する

上記は私によるヒープの実装です。
ここに画像の説明を挿入

おすすめ

転載: blog.csdn.net/li209779/article/details/132227139
おすすめ