【数据结构与算法】二叉树——堆的增删查改

本文介绍了堆的基本概念,包括最大堆和最小堆,并详细阐述了堆的建立、插入、删除等操作。通过代码展示了小堆的实现,包括向上调整和向下调整算法。同时提供了完整的C语言实现源码,包括堆的初始化、插入、删除、判断空、求长度、获取堆顶值、销毁和遍历等功能。
摘要由CSDN通过智能技术生成

🌹作者:云小逸
📝个人主页:云小扬的主页
📝码云:云小扬 (YunXiaoYang003) - Gitee.com
🤟motto:要敢于一个人默默的面对自己,强大自己才是核心。不要等到什么都没有了,才下定决心去做。种一颗树,最好的时间是十年前,其次就是现在!学会自己和解,与过去和解,努力爱自己。希望春天来之前,我们一起面朝大海,春暖花开!🤟
👏专栏:C语言初阶👏专栏:C语言进阶👏专栏:数据结构和算法👏
👏专栏:C++初阶—👏专栏:C++进阶–👏专栏:Linux学习👏

前言

前面我们已经说了关于二叉树的相关概念和二叉树的前、中、后序遍历,今天我们就来学习一下,二叉树的一种形式:堆。
——————————————————————————————


1.堆的基本概念和结构:

a.堆的概念

二叉堆是一种特殊的堆,二叉堆是完全二元树(二叉树)或者是近似完全二元树(二叉树)。二叉堆有两种:最大堆和最小堆。
最大堆:父结点的键值总是大于或等于任何一个子节点的键值;
最小堆:父结点的键值总是小于或等于任何一个子节点的键值。

b.堆的性质

堆中某个节点的值总是不大于或不小于其父节点的值;
堆总是一棵完全二叉树。

c.堆的结构

物理上:一维数组
逻辑上:完全二叉树
小根堆

2.堆的操作

注:插入删除不可以改变堆的性质,即大堆或小堆,本篇代码是以小堆为例子!!!

(1)堆的建立

typedef int HPDataType;
typedef struct Heap
{
	HPDataType* a;
	size_t size;
	size_t capacity;
}HP;

(2)堆的初始化

void HeapInit(HP* php)
{
	assert(php);
	php->a = NULL;
	php->capacity = php->size = 0;
}

(3)堆的插入

思想:向上调整算法

逻辑上:

在这里插入图片描述

物理上:

在这里插入图片描述

交换函数:
void HeapSwap(HPDataType* pa,HPDataType* pb)
{
	HPDataType temp = *pa;
	*pa = *pb;
	*pb = temp;
}
向上调整算法函数
void AdjustUp(HPDataType* a, size_t child)
{
	size_t parent = (child - 1) / 2;
	while (child > 0)
	{
		if (a[child] < a[parent])
		{
			HeapSwap(&a[child], &a[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
			break;
	}
}
插入函数
void HeapPush(HP* php, HPDataType x)
{
	assert(php);//插入之前要想考虑是否要扩容!!!
	if (php->size == php->capacity)
	{
		size_t newnode = php->capacity == 0 ? 4 : php->capacity * 2;
		HPDataType* temp = realloc(php->capacity, sizeof(HPDataType) * newnode);
		if (temp == NULL)
		{
			printf("realloc failed!\n");
			exit(-1);
		}
		php->a = temp;
		php->capacity = newnode;
	}
	php->a[php->size] = x;
	php->size++;
	AdjustUp(php->a, php->size - 1);
}

在这里插入图片描述

(4)堆的删除

思想:向下调整法

在这里插入图片描述

向下调整函数:

void AdjustDown(HPDataType* a, size_t size, size_t root)
{
	size_t parent = root;
	size_t child = parent * 2 + 1;
	while (child < size)
	{
		if (child<size && a[child]>a[child + 1])
		{
			child++;
		}
		if (a[parent] > a[child])
		{
			HeapSwap(&a[parent], &a[child]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
			break;
	}
}

删除函数

void HeapPop(HP* php)
{
	assert(php);
	assert(php->size);
	HeapSwap(&php->a[0], &php->a[php->size - 1]);
	php->size--;
	AdjustDown(php->a, php->size, 0);
}

在这里插入图片描述

(5)判断堆是否为空

bool HeapEmpty(HP* php)
{
	assert(php);
	return php->size==0;
}

(6)求堆的长度

size_t HeapSize(HP* php)
{
	assert(php);
	return php->size;
}

在这里插入图片描述

(7)返回堆顶的值

HPDataType HeapTop(HP* php)
{
	assert(php);
	return php->a[0];
}

在这里插入图片描述

(8)销毁堆

void HeapDestroy(HP* php)
{
	assert(php);
	php->a = NULL;
	php->size = php->capacity = 0;
	free(php);
}

(9)遍历堆

void HeapPrint(HP* php)
{
	assert(php);
	size_t i = 0;
	for (i = 0; i < php->size; i++)
	{
		printf("%d  ", php->a[0]);
	}
	printf("\n");
}

完整源码:

Heap.h文件:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>
typedef int HPDataType;
typedef struct Heap
{
	HPDataType* a;
	size_t size;
	size_t capacity;
}HP;
void HeapInit(HP* php);
void HeapInit(HP* php);
void HeapSwap(HPDataType* pa, HPDataType* pb);
void AdjustUp(HPDataType* a, size_t child);
void HeapPush(HP* php, HPDataType x);
void AdjustDown(HPDataType* a, size_t size, size_t root);
void HeapPop(HP* php);
bool HeapEmpty(HP* php);
size_t HeapSize(HP* php);
HPDataType HeapTop(HP* php);
void HeapDestroy(HP* php);
void HeapPrint(HP* php);

Heap.c文件:

#define _CRT_SECURE_NO_WARNINGS 1
#include"Heap.h"
void HeapInit(HP* php)
{
	assert(php);
	php->a = NULL;
	php->capacity = php->size = 0;
}
void HeapSwap(HPDataType* pa,HPDataType* pb)
{
	HPDataType temp = *pa;
	*pa = *pb;
	*pb = temp;
}
void AdjustUp(HPDataType* a, size_t child)
{
	size_t parent = (child - 1) / 2;
	while (child > 0)
	{
		if (a[child] < a[parent])
		{
			HeapSwap(&a[child], &a[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
			break;
	}
}
void HeapPush(HP* php, HPDataType x)
{
	assert(php);//插入之前要想考虑是否要扩容!!!
	if (php->size == php->capacity)
	{
		size_t newcapacity = php->capacity == 0 ? 4 : php->capacity * 2;
		HPDataType* temp = realloc(php->a, sizeof(HPDataType) * newcapacity);
		if (temp == NULL)
		{
			printf("realloc failed!\n");
			exit(-1);
		}
		php->a = temp;
		php->capacity = newcapacity;
	}
	php->a[php->size] = x;
	php->size++;
	AdjustUp(php->a, php->size - 1);
}
void AdjustDown(HPDataType* a, size_t size, size_t root)
{
	size_t parent = root;
	size_t child = parent * 2 + 1;
	while (child < size)
	{
		if (child<size && a[child]>a[child + 1])
		{
			child++;
		}
		if (a[parent] > a[child])
		{
			HeapSwap(&a[parent], &a[child]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
			break;
	}
}
void HeapPop(HP* php)
{
	assert(php);
	assert(php->size);
	HeapSwap(&php->a[0], &php->a[php->size - 1]);
	php->size--;
	AdjustDown(php->a, php->size, 0);
}
bool HeapEmpty(HP* php)
{
	assert(php);
	return php->size==0;
}
size_t HeapSize(HP* php)
{
	assert(php);
	return php->size;
}
HPDataType HeapTop(HP* php)
{
	assert(php);
	return php->a[0];
}
void HeapDestroy(HP* php)
{
	assert(php);
	php->a = NULL;
	php->size = php->capacity = 0;
	free(php);
}
void HeapPrint(HP* php)
{
	assert(php);
	size_t i = 0;
	for (i = 0; i < php->size; i++)
	{
		printf("%d  ", php->a[i]);
	}
	printf("\n");
}

test.c文件:

#define _CRT_SECURE_NO_WARNINGS 1
#include"Heap.h"
int main(void)
{
	HP hp;
	HeapInit(&hp);
	HeapPush(&hp, 1);
	HeapPrint(&hp);
	HeapPush(&hp, 5);
	HeapPrint(&hp);
	HeapPrint(&hp);
	HeapPush(&hp, 0);
	HeapPrint(&hp);
	HeapPush(&hp, 8);
	HeapPrint(&hp);
	HeapPush(&hp, 3);
	HeapPrint(&hp);
	HeapPush(&hp, 9);
	HeapPrint(&hp);
	HeapPop(&hp);
	HeapPrint(&hp);
	HeapPop(&hp);
	HeapPrint(&hp);
	HeapPop(&hp);
	HeapPrint(&hp);
	printf("%d\n", HeapSize(&hp));
	printf("%d", HeapTop(&hp));
	return 0;
	HeapDestroy(&hp);
}

运行结果截图:

在这里插入图片描述

最后

十分感谢你可以耐着性子把它读完和我可以坚持写到这里,送几句话,对你,也对我:

  1. 我的人生是一栋只能建造一次的楼房,我必须让它精确无比,不能有一厘米差池——所以,我太紧张,害怕行差步错。
    2.我不想要那种一眼就可以看到死的人生,那种 “我们到底是活了365天,还是活了一天却重复了364遍” 的悲哀,我实在无法想象日复一日的重复一天的人生还有什么意义,我才20岁,人生难道就此再无波澜和际遇?
    3.这对我来说依旧可怕,我害怕后果,害怕行差步错,害怕放弃了所有 却依旧失去了她。
    4.只问自由,只问盛放,只问深情,只问初心,只问勇敢,无问西东
    5.少发脾气。收敛脾气,内心才有元气。不同层次无需讲道理;不同位置无需争辩对错;三观不合无需探讨私事。
    6.在感情中及时止损,该说拜拜的人不回头挽留。
    7.不刻意满足别人的期待而活着。敢做真实的自己,才有人爱上真实的你。按照自己喜欢的方式去生活,越多对的人会向你靠近。

最后如果觉得我写的还不错,请不要忘记点赞✌,收藏✌,加关注✌哦(。・ω・。)

愿我们一起加油,奔向更美好的未来,愿我们从懵懵懂懂的一枚菜鸟逐渐成为大佬。加油,为自己点赞!

评论 127
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

云小逸

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值