本节复习堆, 堆分为逻辑结构和物理结构, 堆的物理结构是一个数组。 堆的逻辑结构是一个二叉树。 其中堆又分为大堆和小堆。
那么如何分辨大堆和小堆?
分辨大堆和小堆我们要看堆的逻辑结构,对于一棵二叉树。 每个非叶子节点都可能有一个左孩子或者右孩子, 或者两个孩子全部都有。
而堆是一个完全二叉树。 也就是说, 每个非叶子节点都有两个孩子或者有一个左孩子。
那么, 大堆就是每个父亲节点的值都大于左孩子和右孩子的值。
小堆就是每个父亲节点的值都小于左孩子和右孩子的值。
现在我们来实现一下堆的结构。
目录
准备文件
我们先准备三个文件, 一个main.c用于写main函数调试。一个.h文件用于函数声明, 一个.c文件函数实现.
建立结构体
首先包含以下头文件和重定义一下要保存的数据。 便于后续的维护。
////////////////////////////////////////堆的增删查改////////////////////////////////////////////////////////////
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
typedef int HPDataType;
然后创建结构体, 因为堆得物理结构是一块数组。 所以我们可以使用顺序表的数据结构。
////////////////////////////////////////堆的增删查改//////////////////////////////////////////////////////////// #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 AdjustDown(HPDataType* arr, int n, int parent)
{
int child = (parent * 2) + 1;//假设左孩子比右孩子小
while (child < n)
{
if (child + 1 < n && arr[child + 1] < arr[child])
{
child++;//如果左孩子比右孩子大, 就让孩子节点变成指向右孩子
}
//
if (arr[child] < arr[parent])
{
HPDataType tmp = arr[child];
arr[child] = arr[parent];
arr[parent] = tmp;//交换数值
}
//
parent = child;
child = (child * 2) + 1;
}
}
向上排序算法
堆的向上排序算法在堆的数据插入的时候需要用到。 逻辑很简单, 如图:

如下为代码:
//向上调整算法,适用于新插入数据时形成新的堆
void AdjustUp(HPDataType* arr, int n, int parent)
{
int child = n - 1;
parent = (child - 1) / 2;
while (child > 0) //当孩子节点大于大于0
{
if (arr[child] < arr[parent]) //如果孩子节点小于父亲节点就交换位置
{
HPDataType tmp = arr[child];
arr[child] = arr[parent];
arr[parent] = tmp;
}
child = parent;//孩子节点到父亲节点位置
parent = (child - 1) / 2;//父亲节点位置再到自己的父亲节点位置。
}
}
堆的初始化
.h函数声明
////////////////////////////////////////堆的增删查改////////////////////////////////////////////////////////////
#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 HeapInit(HP* php);
.c函数实现
//堆得初始化
void HeapInit(HP* php)
{
php->_a = (HPDataType*)malloc(sizeof(HPDataType) * 4);
if (php->_a == NULL)
{
perror("初始化失败!\n");
return;
}
php->_capacity = 4;
php->_size = 0;
}
数据插入
.h函数声明
///////////////////////////////////////堆的增删查改////////////////////////////////////////////////////////////
#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 HeapInit(HP* php);
//堆的插入
void HeapPush(HP* php, HPDataType x);
.c函数实现
//向上调整算法,适用于新插入数据时形成新的堆
void AdjustUp(HPDataType* arr, int n, int parent)
{
int child = n - 1;
parent = (child - 1) / 2;
while (child > 0)
{
if (arr[child] < arr[parent])
{
HPDataType tmp = arr[child];
arr[child] = arr[parent];
arr[parent] = tmp;
}
child = parent;
parent = (child - 1) / 2;
}
}
//堆的插入
void HeapPush(HP* php, HPDataType x)
{
assert(php);
//
if (php->_size == php->_capacity)
{
int newcapacity = php->_capacity * 2;
HPDataType* tmp = (HPDataType*)realloc(php->_a, sizeof(HPDataType) * newcapacity);
if (tmp == NULL)
{
perror("插入失败");
return;
}
//
php->_a = tmp;
php->_capacity = newcapacity;
}
php->_a[php->_size] = x;
php->_size++;
//想上调整算法。
AdjustUp(php->_a, php->_size, (php->_size - 1) / 2);
}
数据删除
.h函数声明
////////////////////////////////////////堆的增删查改////////////////////////////////////////////////////////////
#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 HeapInit(HP* php);
//堆的插入
void HeapPush(HP* php, HPDataType x);
//堆的删除数据
void HeapPop(HP* php);
.c函数实现
//向下调整算法
void AdjustDown(HPDataType* arr, int n, int parent)
{
int child = (parent * 2) + 1;
while (child < n)
{
if (child + 1 < n && arr[child + 1] < arr[child])
{
child++;
}
//
if (arr[child] < arr[parent])
{
HPDataType tmp = arr[child];
arr[child] = arr[parent];
arr[parent] = tmp;//交换数值
}
//
parent = child;
child = (child * 2) + 1;
}
}
//堆的删除数据
void HeapPop(HP* php)
{
assert(php);
assert(php->_a);
//
HPDataType tmp = php->_a[0];
php->_a[0] = php->_a[php->_size - 1];
php->_a[php->_size - 1] = tmp;
//将第一个数据和第二个数据交换, 然后使用向下调整算法
php->_size--;
AdjustDown(php->_a, php->_size, 0);
}
取堆顶的数据
.h函数声明
////////////////////////////////////////堆的增删查改////////////////////////////////////////////////////////////
#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 HeapInit(HP* php);
//堆的插入
void HeapPush(HP* php, HPDataType x);
//堆的删除数据
void HeapPop(HP* php);
//取堆顶的数据
HPDataType HeapTop(HP* php);
.c函数实现
//取堆顶的数据
HPDataType HeapTop(HP* php)
{
assert(php);
assert(php->_a);
//
return php->_a[0];
}
堆的数据个数
.h函数声明
////////////////////////////////////////堆的增删查改////////////////////////////////////////////////////////////
#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 HeapInit(HP* php);
//堆的插入
void HeapPush(HP* php, HPDataType x);
//堆的删除数据
void HeapPop(HP* php);
//取堆顶的数据
HPDataType HeapTop(HP* php);
//堆的数据个数
int HeapSize(HP* php);
.c函数实现
//堆的数据个数
int HeapSize(HP* php)
{
assert(php);
return php->_size;
}
堆的判空
.h函数声明
////////////////////////////////////////堆的增删查改////////////////////////////////////////////////////////////
#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 HeapInit(HP* php);
//堆的插入
void HeapPush(HP* php, HPDataType x);
//堆的删除数据
void HeapPop(HP* php);
//取堆顶的数据
HPDataType HeapTop(HP* php);
//堆的数据个数
int HeapSize(HP* php);
//堆的判空
bool HeapEmpty(HP* php);
.c函数实现
//堆的判空
bool HeapEmpty(HP* php)
{
assert(php);
return php->_size == 0;
}
堆的销毁
.h函数声明
////////////////////////////////////////堆的增删查改////////////////////////////////////////////////////////////
#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 HeapInit(HP* php);
//堆的插入
void HeapPush(HP* php, HPDataType x);
//堆的删除数据
void HeapPop(HP* php);
//取堆顶的数据
HPDataType HeapTop(HP* php);
//堆的数据个数
int HeapSize(HP* php);
//堆的判空
bool HeapEmpty(HP* php);
//堆的销毁
void HeapDestory(HP* php);
.c函数实现
//堆的销毁
void HeapDestory(HP* php)
{
assert(php->_a);
free(php->_a);
php->_a = NULL;
}

1101





