堆的概念到代码实现

本文深入探讨了堆数据结构,包括大根堆与小根堆的定义和性质。详细介绍了堆的创建、插入、删除等操作的算法实现,如向下调整和向上调整过程,并提供了相关代码示例。通过对堆的全面理解,有助于提升数据结构的实际应用能力。
摘要由CSDN通过智能技术生成

目录

1、什么是堆

2、堆有什么性质

3、堆的实现

3.1、堆向下调整算法       

3.2堆的创建

3.3堆的插入

3.4堆的删除


1、什么是堆

一颗完全二叉树且其任意节点都比其孩子节点大(小),将这种数据结构成为大根堆(小根堆)。

2、堆有什么性质

  • 堆中某个结点的值总是不大于或者不小于其父节点的值
  • 堆必定是一颗完全二叉树

  

 

 小根堆存储结构                                             大根堆存储结构

如图,最上边的元素称为堆顶,易知:

  • 堆顶的元素要么是最大的,要么是最小的
  • 每一条路径一定事升序或者降序

3、堆的实现

3.1、堆向下调整算法       

现在我们给出一个数组,逻辑上是一颗完全二叉树,我们通过从根节点开始的向下调整算法可以把它调整为一个小堆。注意:向下调整算法有一个前提——左右子树必须是一个堆,才能调整。

如图,以27为堆顶的左右子树都是小堆,只有根节点不满足,这种情况就可以通过将根节点向下调整到合适的位置来形成堆。

  1. 让27和它较小的一个孩子进行交换,即27和15进行交换
  2. 再让27和它较小的孩子进行交换,即27和18进行交换
  3. 再让27和它较小的孩子进行交换,即27和25进行交换
  4. 此时,形成堆——如下图

3.2堆的创建

和上边同理,若给的数据,初始化堆时,左右子树都不是堆的结构,则需要,每次调整一次,都要对其下的子树进行新的检查和调整。

// 堆的构建
//创建堆的时候需要用到向下调整
void HeapCreate(Heap* hp, HPDataType* array, int size,PFUNC pCompare)
{
	assert(hp);
	//1、将hp指向的堆结构体初始化好
	hp->array = (HPDataType*)malloc(sizeof(HPDataType) * size);
	if (hp->array == NULL)
	{
		assert(0);
		return;
	}
	hp->capacity = size;
	//2、将数组中的元素往堆中存放
	memcpy(hp->array, array, size * sizeof(HPDataType));
	hp->size = size;
	hp->pCompare = pCompare;
	//3、需要对hp->array中的元素进行调整
	
	//BubbleSort(hp->array, size);——方法可以,但不够好,时间复杂度太高
	for (int root = (size - 2) / 2; root >= 0;root--)
		AdjustDown(hp, root);
}



//堆的向下调整
void AdjustDown(Heap*hp, int parent)
{
	int child = parent*2+1;
	int size = hp->size;
	while (child < size)
	{
		//1、找parent较小的孩子,先默认让parent = 他的左孩子,因为是完全二叉树,很有可能parent有左孩子没有右孩子
		if (child + 1 < size && hp->pCompare(hp->array[child+1],hp->array[child]))
		{
			child += 1;
		}
		//2、检测parent是否满足堆的特性
		if (hp->pCompare(hp->array[child], hp->array[parent]))
		{
			Swap(&hp->array[parent], &hp->array[child]);

			//大的元素往下走,可能导致子树也不满足堆的性质
			parent = child;
			child = parent * 2 + 1;
		}
		else
			return;
	}
}

3.3堆的插入

// 堆的插入
void HeapPush(Heap* hp, HPDataType x)
{
	//1、将要插入的元素放入堆所在的数组中
	CheckCapicity(hp);//扩容方法
	hp->array[hp->size] = x;
	hp->size++;
	//2、判断新节点与其父节点是否满足堆的特性,不满足的话,需要进行调整
	Adjustup(hp, hp->size - 1);
}

void CheckCapicity(Heap* hp)
{
	assert(hp);
	if (hp->size == hp->capacity)
	{
		int newCapicity = hp->capacity * 2;
		HPDataType* tem = (HPDataType*)malloc(sizeof(HPDataType) * newCapicity);
		if (NULL == tem)
		{
			assert(0);
			return;
		}
		memcpy(tem, hp->array, sizeof(HPDataType) * hp->size);
		free(hp->array);
		hp->array = tem;
		hp->capacity = newCapicity;
	}
}

void Adjustup(Heap*hp, int child)
{
	int parent = (child - 1) / 2;
	while (child)
	{
		if (hp->pCompare(hp->array[parent],hp->array[child]))
		{
			Swap(&hp->array[parent], &hp->array[child]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
			return;
	}
}

3.4堆的删除

 堆删除时删除的是堆顶元素。

// 堆的删除
void HeapPop(Heap* hp)
{
	assert(hp);
	if (HeapEmpty(hp))
		return;
	//1、将堆顶元素与堆中最后一个元素进行交换
	Swap(&hp->array[0], &hp->array[hp->size - 1]);
	//2、将堆中有效元素减少一个
	hp->size--;
	//3、将堆顶元素往下调整
	AdjustDown(hp, 0);
}

评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值