ヒープインターフェースの実装(ソースコード+図付き)
記事ディレクトリ
序文
この記事では主に二分木でのヒープの追加・削除・チェック・修正などのインターフェースの実装を紹介し、最後に全体のソースコードを添付しています!
1. 構造を定義する
コードは次のとおりです (例)。
typedef int HPDataType;
typedef struct Heap
{
HPDataType* a; //定义数组二叉树
int size; //二叉树结点个数
int capacity; //二叉树容量(考虑增容)
}HP;
2. インターフェース実装(添付ソリューション+ソースコード)
ここには全部で 11 のインターフェイスがあり、1 つずつ説明します (イラスト + ソースコード)
1.ヒープを初期化する
二分木におけるヒープの格納構造は配列なので、 2つのインターフェースの初期化と破棄はシーケンステーブルやその他のデータ構造と同じなので、ここではあまり紹介しません!
コードは次のとおりです (例)。
void HeapInit(HP* hp)
{
assert(hp);
hp->a = NULL;
hp->size = hp->capacity = 0;
}
2. ヒープを破棄する
コードは次のとおりです (例)。
void HeapDestroy(HP* hp)
{
assert(hp);
free(hp->a);
hp->capacity = hp->size = 0;
}
3.テールプラグデータ
コードは次のとおりです (例)。
void HeapPush(HP* hp, HPDataType x)
{
assert(hp);
if (hp->size == hp->capacity)
{
size_t newCapacity = hp->capacity == 0 ? 4 : hp->capacity * 2;
HPDataType* tmp = realloc(hp->a, sizeof(HPDataType) * newCapacity);
if (tmp == NULL)
{
printf("realloc fail\n");
exit(-1);
}
hp->a = tmp;
hp->capacity = newCapacity;
}
hp->a[hp->size] = x;
hp->size++;
}
ここで注意してください: 大きなヒープであろうと小さなヒープであろうと、それは親ノード > または < 子ノード(二分木の性質) を満たす必要があります。ここでは上下調整を使用します! データをプッシュすると、このパスのデータのみが変更されます!
①上方調整
以下に示すように、いくつかのデータを挿入するとします。上向きに調整すると、1 つのパスのみが変更されます。! !
上方調整は、親
コードは次のとおりです (例)。
void AdjustUp(int* a, int child)
{
assert(a);
int parent = (child - 1) / 2;
//while (parent >= 0)
while (child > 0)
{
if (a[child] > a[parent])
{
Swap(&a[child], &a[parent]);
child = parent;
parent = (child - 1) / 2;
}
else
{
break;
}
}
}
(2) 交換機能
関数パラメーターを渡す場合、仮パラメーターは実パラメーターの一時的なコピーであるため、ポインターを渡す必要があります。
コードは次のとおりです (例)。
void Swap(HPDataType * px, HPDataType * py)
{
HPDataType tmp = *px;
*px = *py;
*py = tmp;
}
(3)下向きに調整
ここでパラメーターに注意してください: 親ノードから。最高点は最小値です。
下方調整は、トップ (最高ノード) が最小値であることを確認する必要があります!
4.印刷データ
二分木の格納構造は配列であるため、印刷時に直接トラバースできます。
コードは次のとおりです (例)。
void HeapPrint(HP* hp)
{
for (int i = 0; i < hp->size; ++i)
{
printf("%d ", hp->a[i]);
}
printf("\n");
}
5.空かどうかを判断する
コードは次のとおりです (例)。
bool HeapEmpty(HP* hp)
{
assert(hp);
return hp->size == 0;
}
6. ノード数
コードは次のとおりです (例)。
int HeapSize(HP* hp)
{
assert(hp);
return hp->size;
}
7. ヒープトップデータ
配列に対して null 操作を実行することを忘れないでください。そうしないと、ワイルド ポインターの問題が発生します。
コードは次のとおりです (例)。
HPDataType HeapTop(HP* hp)
{
assert(hp);
assert(!HeapEmpty(hp));
return hp->a[0];
}
8. ヒープの一番上にあるデータを削除する
ここで注意してください: データを削除した後、ヒープのプロパティ構造(Adjustdown) を保護する必要があります。
3. ソースコード表示
(1) 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;
void AdjustUp(int* a, int child);//向上调整
void AdjustDown(int* a, int n, int parent);//向下调整
void Swap(HPDataType* px, HPDataType* py);//交换
void HeapInit(HP* hp);//初始化堆
void HeapDestroy(HP* hp);//销毁堆
void HeapPush(HP* hp, HPDataType x);//尾插数据
void HeapPop(HP* hp);//删除堆顶的数据
HPDataType HeapTop(HP* hp);//取堆顶的数据
void HeapPrint(HP* hp);//打印堆(数组)
bool HeapEmpty(HP* hp);//判断堆是否为空
int HeapSize(HP* hp);//堆结点个数
(2) Heap.c(インターフェース関数の実装)
コードは次のとおりです (例)。
#include "Heap.h"
void Swap(HPDataType * px, HPDataType * py)
{
HPDataType tmp = *px;
*px = *py;
*py = tmp;
}
void HeapInit(HP* hp)
{
assert(hp);
hp->a = NULL;
hp->size = hp->capacity = 0;
}
void HeapDestroy(HP* hp)
{
assert(hp);
free(hp->a);
hp->capacity = hp->size = 0;
}
void AdjustUp(int* a, int child)
{
assert(a);
int parent = (child - 1) / 2;
//while (parent >= 0)
while (child > 0)
{
if (a[child] > a[parent])
{
Swap(&a[child], &a[parent]);
child = parent;
parent = (child - 1) / 2;
}
else
{
break;
}
}
}
void HeapPrint(HP* hp)
{
for (int i = 0; i < hp->size; ++i)
{
printf("%d ", hp->a[i]);
}
printf("\n");
}
void HeapPush(HP* hp, HPDataType x)
{
assert(hp);
if (hp->size == hp->capacity)
{
size_t newCapacity = hp->capacity == 0 ? 4 : hp->capacity * 2;
HPDataType* tmp = realloc(hp->a, sizeof(HPDataType) * newCapacity);
if (tmp == NULL)
{
printf("realloc fail\n");
exit(-1);
}
hp->a = tmp;
hp->capacity = newCapacity;
}
hp->a[hp->size] = x;
hp->size++;
AdjustUp(hp->a, hp->size - 1);
}
bool HeapEmpty(HP* hp)
{
assert(hp);
return hp->size == 0;
}
int HeapSize(HP* hp)
{
assert(hp);
return hp->size;
}
HPDataType HeapTop(HP* hp)
{
assert(hp);
assert(!HeapEmpty(hp));
return hp->a[0];
}
void AdjustDown(int* a, int n, int parent)
{
int child = parent * 2 + 1;
while (child < n)
{
// 选出左右孩子中小的那一个
if (child + 1 < n && a[child + 1] < a[child])
{
++child;
}
// 如果小的孩子小于父亲,则交换,并继续向下调整
if (a[child] < a[parent])
{
Swap(&a[child], &a[parent]);
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
// 删除堆顶的数据
void HeapPop(HP* hp)
{
assert(hp);
assert(!HeapEmpty(hp));
Swap(&hp->a[0], &hp->a[hp->size - 1]);
hp->size--;
AdjustDown(hp->a, hp->size, 0);
}
(3) test.c (テスト+メイン関数)
コードは次のとおりです (例)。
#include"Heap.h"
void TestHeap()
{
int a[] = {
70, 56, 30, 25, 15, 10, 75 };
HP hp;
HeapInit(&hp);
for (int i = 0; i < sizeof(a) / sizeof(a[0]); ++i)
{
HeapPush(&hp, a[i]);
}
HeapPrint(&hp);
HeapPop(&hp);
HeapPrint(&hp);
HeapPop(&hp);
HeapPrint(&hp);
HeapPop(&hp);
HeapPrint(&hp);
HeapPop(&hp);
HeapPrint(&hp);
HeapDestroy(&hp);
}
要約する
以上が本日の言いたいことですが、この記事では二分木におけるヒープのインターフェース実装を紹介します(ソリューションとソースコードを添付)!
私のブログが役に立ったら、忘れずに 3 回サポートしてください。