将一个关键码的集合K = {k0 , k1,k2,k3……kn-1}把他所有元素按完全二叉树的存储方式放在一个一维数组中,并且满足双亲节点大于孩子节点,或者双亲节点小于孩子节点将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。
#pragma once
#include
#include
#include
#include
typedef int Datatype;
typedef int (*func)(Datatype left, Datatype right);
typedef struct Heap {
Datatype* arr;
int capacity;
int size;
func Comper;
}Heap;
//堆的创建 用回调函数判断是要创建小堆还是大堆
void HeapCreate(Heap* p, Datatype *arr, int size, func Comper);
//向上调整
void HeapAdjustup(Heap* p, int child);
//向下调整
void HeapAdjustDown(Heap* p, int parent);
//堆的插入
void HeapPush(Heap* p, Datatype data);
//堆的移除
void HeapErase(Heap* p);
//获取堆顶元素
Datatype HeapTop(Heap* p);
//获取堆的长度
int HeapSize(Heap* p);
//堆是否为空
int HeapEmpty(Heap* p);
//堆的销毁
void HeapDestroy(Heap* p);
//堆的扩容
void HeapCheakCapacity(Heap* p);
#include "Heap.h"
//交换函数
void Swap(Datatype* left, Datatype* right) {
Datatype temp = *left;
*left = *right;
*right = temp;
}
int Max(Datatype left, Datatype right)
{
return left > right;
}
int Min(Datatype left, Datatype right)
{
return left < right;
}
//只是在除了根节点以外 他的两个子树也是堆结构的情况下才成立
//而且你要小堆我得改一次大于号,远没有回调函数那样的便捷
//回调函数忘记了可以自己手动实现一次qsort
//冒泡排序
void BobSort(Datatype* arr,int size) {
for (int i = 0; i < size - 1; i++) {
for (int j = 0; j < size - 1 - i; j++) {
if (arr[j - 1] > arr[j]) {
Swap(&arr[j - 1], &arr[j]);
}
}
}
}
//向下调整
void HeapAdjustDown(Heap* p, int parent)
{
int child = (parent << 1) + 1;
int size = p->size;
while (child < size) {
//因为我么对parent * 2 + 1找到的是这个节点对应的左孩子
//要是我右孩子还小呢
//利用回调函数找到更小的那一个将child指针移动到右孩子那块
if (child + 1 < size && p->Comper(p->arr[child + 1], p->arr[child])) {
child += 1;
}
//是否满足堆的特性
if (p->Comper(p->arr[child], p->arr[parent])) {
Swap(&p->arr[parent], &p->arr[child]);
parent = child;
child = (parent << 1) + 1;
}
else {
return;
}
}
}
//向上调整
void HeapAdjustup(Heap* p, int child)
{
int parent = (child - 1) >> 1;
while (child) {
if (p->Comper(p->arr[child], p->arr[parent])) {
Swap(&p->arr[child], &p->arr[parent]);
child = parent;
parent = (child - 1) >> 1;
}
else {
return;
}
}
}
//堆的扩容
void HeapCheakCapacity(Heap* p)
{
assert(p);
//判断是否需要扩容
if (p->size == p->capacity) {
//把容量变成原来的两倍
int NewCapaty = p->capacity << 1;
//从堆上开辟新的内存空间
Datatype* temp = (Datatype*)malloc(sizeof(Datatype) * NewCapaty);
if (NULL == temp) {
assert(0);
return;
}
//把原来的数据拷贝
memcpy(temp, p->arr, sizeof(Datatype) * p->size);
//释放旧空间改变指针指向
free(p->arr);
p->arr = temp;
p->capacity;
}
}
//堆的创建
// 创建堆的时候需要用到向下调整
void HeapCreate(Heap* p, Datatype *arr, int size, func Comper)
{
assert(p);
//动态申请内存完成堆的初始化
p->arr = (Datatype*)malloc(sizeof(Datatype) * size);
//检测是否成功开辟空间
if (NULL == p->arr) {
assert(0);
return;
}
//更新容量
p->capacity = size;
//把你要调整的数据放在你创建的堆里面
memcpy(p->arr, arr, sizeof(Datatype) * size);
p->size = size;
p->Comper = Comper;
for (int root = (size - 2) / 2; root >= 0; root--)
{
HeapAdjustDown(p, root);
}
}
//插入
void HeapPush(Heap* p, Datatype data)
{
HeapCheakCapacity(p);
p->arr[p->size] = data;
p->size++;
HeapAdjustup(p, p->size - 1);
}
void HeapErase(Heap* p)
{
if (HeapEmpty(p)) {
return;
}
Swap(&p->arr[0], &p->arr[p->size - 1]);
p->size--;
HeapAdjustDown(p, 0);
}
//获取堆顶元素
//因为我们是顺序表构建的堆
//那他的0号下标必是root
Datatype HeapTop(Heap* p)
{
assert(p);
return p->arr[0];
}
//获取堆的长度
int HeapSize(Heap* p)
{
assert(p);
return p->size;
}
//检验堆是否为空
int HeapEmpty(Heap* p)
{
assert(p);
return 0 == p->size;
}
//堆的销毁
void HeapDestroy(Heap* p)
{
assert(p);
//看是否不为空 然后就直接free 最后更新堆的数据
if (p->arr) {
free(p->arr);
p->arr = NULL;
p->capacity = 0;
p->size = 0;
}
}
int main() {
int arr[] = { 49, 27, 37, 65, 28, 34, 25, 15, 18, 19 };
Heap p;
HeapCreate(&p, arr, sizeof(arr) / sizeof(arr[0]), Min);
printf("top = %d\n", HeapTop(&p));
printf("size = %d\n", HeapSize(&p));
HeapPush(&p, 10);
printf("top = %d\n", HeapTop(&p));
printf("size = %d\n", HeapSize(&p));
HeapErase(&p);
printf("top = %d\n", HeapTop(&p));
printf("size = %d\n", HeapSize(&p));
HeapDestroy(&p);
}
//向下调整
void HeapAdjustDown(Heap* p, int parent)
{
int child = (parent << 1) + 1;
int size = p->size;
while (child < size) {
//因为我么对parent * 2 + 1找到的是这个节点对应的左孩子
//要是我右孩子还小呢
//利用回调函数找到更小的那一个将child指针移动到右孩子那块
if (child + 1 < size && p->Comper(p->arr[child + 1], p->arr[child])) {
child += 1;
}
//是否满足堆的特性
if (p->Comper(p->arr[child], p->arr[parent])) {
Swap(&p->arr[parent], &p->arr[child]);
parent = child;
child = (parent << 1) + 1;
}
else {
return;
}
}
}
//向上调整
void HeapAdjustup(Heap* p, int child)
{
int parent = (child - 1) >> 1;
while (child) {
if (p->Comper(p->arr[child], p->arr[parent])) {
Swap(&p->arr[child], &p->arr[parent]);
child = parent;
parent = (child - 1) >> 1;
}
else {
return;
}
}
}
//堆的扩容
void HeapCheakCapacity(Heap* p)
{
assert(p);
//判断是否需要扩容
if (p->size == p->capacity) {
//把容量变成原来的两倍
int NewCapaty = p->capacity << 1;
//从堆上开辟新的内存空间
Datatype* temp = (Datatype*)malloc(sizeof(Datatype) * NewCapaty);
if (NULL == temp) {
assert(0);
return;
}
//把原来的数据拷贝
memcpy(temp, p->arr, sizeof(Datatype) * p->size);
//释放旧空间改变指针指向
free(p->arr);
p->arr = temp;
p->capacity;
}
}
//堆的创建
// 创建堆的时候需要用到向下调整
void HeapCreate(Heap* p, Datatype *arr, int size, func Comper)
{
assert(p);
//动态申请内存完成堆的初始化
p->arr = (Datatype*)malloc(sizeof(Datatype) * size);
//检测是否成功开辟空间
if (NULL == p->arr) {
assert(0);
return;
}
//更新容量
p->capacity = size;
//把你要调整的数据放在你创建的堆里面
memcpy(p->arr, arr, sizeof(Datatype) * size);
p->size = size;
p->Comper = Comper;
for (int root = (size - 2) / 2; root >= 0; root--)
{
HeapAdjustDown(p, root);
}
}
这里用这个数组进行堆的创建
int arr[] = { 49, 27, 37, 65, 28, 34, 25, 15, 18, 19 };
//插入
void HeapPush(Heap* p, Datatype data)
{
HeapCheakCapacity(p);
p->arr[p->size] = data;
p->size++;
HeapAdjustup(p, p->size - 1);
}
还是刚刚这个数组
int arr[] = { 49, 27, 37, 65, 28, 34, 25, 15, 18, 19 };
我插入一个99
void HeapErase(Heap* p)
{
if (HeapEmpty(p)) {
return;
}
Swap(&p->arr[0], &p->arr[p->size - 1]);
p->size--;
HeapAdjustDown(p, 0);
}
还是刚刚的数组
//获取堆顶元素
//因为我们是顺序表构建的堆
//那他的0号下标必是root
Datatype HeapTop(Heap* p)
{
assert(p);
return p->arr[0];
}
//获取堆的长度
int HeapSize(Heap* p)
{
assert(p);
return p->size;
}
//检验堆是否为空
int HeapEmpty(Heap* p)
{
assert(p);
return 0 == p->size;
}
//堆的销毁
void HeapDestroy(Heap* p)
{
assert(p);
//看是否不为空 然后就直接free 最后更新堆的数据
if (p->arr) {
free(p->arr);
p->arr = NULL;
p->capacity = 0;
p->size = 0;
}
}
以上代码用的都是跟顺序表一个套路,我在此就不赘述了,顺序表还不会写的同学可以移步这篇文章
数据结构 严薇敏 顺序表的实现(增 删 改)及其使用方法详解