[数据结构入门]第六篇:数据结构之堆

系列文章目录

前言

因为这篇先从简单入手【二叉树的应用之堆】的实现,需要对二叉树有所了解, 这里先大概 描述二叉树及其性质,便于理解堆。下篇会对树、二叉树等做详细讲解。

一、二叉树的概念及性质

1.二叉树的概念

一棵二叉树是结点的一个有限集合,该集合:

  1. 或者为空
  2. 由一个根节点加上两棵别称为左子树和右子树的二叉树组成
    在这里插入图片描述

2.二叉树的性质

  1. 二叉树不存在度大于2的结点
  2. 二叉树的子树有左右之分,次序不能颠倒,因此二叉树是有序树

3.特殊的二叉树

  1. 满二叉树:一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。也就是说,如果一个二叉树的层数为K,且结点总数是(2^k)-1 ,则它就是满二叉树。
  2. 完全二叉树:完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树而引出来的。对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对应时称之为完全二叉树。 要注意的是满二叉树是一种特殊的完全二叉树
    在这里插入图片描述
    通俗的说 完全二叉树前k-1层都是满的,最后一层k深度不一定满,要求从左到右是连续的。

二、堆的概念及性质

1.堆的概念

  1. 如果有一个关键码的集合K = { k0,k1,k2,…,kn-1 },把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中,并满足:Ki <= K2i+1且Ki <=K2i+2 (Ki >=K2i+1 且Ki >=K2i+2 ) i = 0,1,2…,则称为小堆(或大堆)。
  2. 将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。
    在这里插入图片描述

2.堆的性质

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

三、堆的实现

1.用数组定义堆结构:Struct Heap

代码如下

typedef int HDataType;
typedef struct Heap
{
	HDataType* a;//数组
	int size;//大小
	int capacity;//容量
}HP;

2.堆的初始化:HeapInit

代码如下

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

3.交换两个数Swap函数

代码如下

void Swap(HDataType*p1, HDataType* p2)
{
	HDataType* tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}

4.堆向上调整函数:AdjustUp

在这里插入图片描述
代码如下

void Adjustup(HP* php, int child)
{
	int parent = child - 1 / 2;
	//while(parent>=0)  因为父亲=0 进来一次 孩子=父亲=0  父亲计算后=0-1/2  =1 又上去一次 死循环  所以使用 孩子判断
	while (child>0)
	{
		if (php->a[child] < php->a[parent])//小根堆
		{
			Swap(&php->a[child], &php->a[parent]);//交换两个值
			child = parent;//往上走迭代
			parent = child - 1 / 2;//找父亲
		}
		else//已成为堆
		{
			break;//无需调整
		}
	}
}

思路:通过上调的位置(孩子位) 找到其父亲,判断两个值大小,[小堆]如果孩子小于父亲,将两个值交换,再将父亲的值给给孩子(孩子向上走) 在计算当前更新后孩子的父亲 向上迭代着走 直到孩子=0
思考:为什么不用父亲>=0做循环条件?
当父亲=0;继续时父亲的值给给孩子 孩子计算下一个父亲0-1/2,结果依然0存在死循环。

5.堆向下调整函数:AdjustDown

在这里插入图片描述代码如下

void AdjustDown(HP* php, int n, int parent)//数组大小
{
	int minChild = parent * 2 + 1;//默认小孩子是左孩子
	while (minChild<n)//?防止越界数组
	{
		if (php->a[minChild]<n && php->a[minChild + 1] > php->a[minChild])//找出小的那个孩子
		{//防止数组越界   
			minChild++;
		}//小孩子右孩子
		if (php->a[minChild] < php->a[parent])//目前小根堆  叛逆
		{
		Swap(&php->a[minChild], &php->a[parent]);//交换
		parent = minChild;
		minChild = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

思路:找出小的那个孩子 [小堆]如果父亲大于孩子 交换 孩子位置给父亲 向下迭代

6.堆的插入:HeapPush

代码如下

void HeapPush(HP* php, HDataType x)
{
	assert(php);
	if (php->size == php->capacity)
	{
		int newCapaCity = php->capacity == 0 ? 4 : php->capacity * 2;
		HDataType* tmp = (HDataType*)realloc(php->a, newCapaCity*sizeof(HDataType));//开辟大小易错
		if (tmp == NULL)
		{
			perror("realloc fail");
			exit(-1);
		}
		php->a = tmp;
		php->capacity = newCapaCity;
	}
	php->a[php->size] = x;
	php->size++;
	AdjustUp(php->a, php->size-1);//从哪个位置向上调整?
}

思路:插入元素 更新size 向上调整 保持堆的形态

7删除堆顶元素:HeapPop

代码如下

void HeapPop(HP* php)
{
	assert(php);
	assert(!HeapEmpty(php));
	Swap(php->a[0], php->a[php->size - 1]);//交换第一个和最后一个位置
	php->size--;删除最后一个位置
    AdjustDown(php->a, php->size, 0);//调整保持堆形态
}

思路:【找次大或次小】保持堆形态 为了不破坏父子关系 头尾数据交换后删除尾巴 通过向下调整保持堆形态

8…获取堆顶元素:HeapTop

代码如下

HDataType HeapTop(HP* php)
{
	assert(php);
	assert(!HeapEmpty(php));
	return php->a[0];//返回第一位的值
}

9.堆的判空:HeapEmpty

代码如下

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

10.堆的大小:HeapSize

代码如下

int HeapSize(HP* php)
{
	assert(php);
	return php->size;//size位大小
}

11.堆的打印:HeapPrint

代码如下

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

12.堆的销毁:HeapDestroy

代码如下

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

总结

以上就是我对数据结构中二叉树的应用的一些认识,如果有问题,请大家帮忙指出。掌握堆的特点及如何保持堆形态的调整,遇到问题多画图 想明白多上手敲代码。(监督自己💪)

今日语录✍️
知不足而奋进 望远山而前行💖

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值