【浅谈数据结构】堆(满二叉树)基本概念及函数实现(附源码)

1. 堆的概念

1.1 定义

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

1.2 特性

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

1.3 堆的种类

堆按照特性1可以区分为大堆(大根堆)或者小堆(小根堆) 大堆就是每个子树的根节点都要比子节点大的树

在这里插入图片描述

1.4 常用场景

  1. 堆(Heap)是计算机科学中一类特殊的数据结构的统称。堆通常是一个可以被看做一棵完全二叉树的数组对象。
  2. 将根结点最大的堆叫做最大堆或大根堆,根结点最小的堆叫做最小堆或小根堆。常见的堆有二叉堆、斐波那契堆等。
  3. 堆是非线性数据结构,相当于一维数组,有两个直接后继。

2.堆函数 源码实现

1. HeapInit

初始化堆

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

2. HeapDestroy

销毁堆 ,返回堆所占用的空间

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

3. HeapPush

数组尾部插入数据 ,并且交换根节点与尾部的数据 然后调整堆的数据(根据大/小堆选择向上/向下调整) 使堆保持原来的性质

void HeapPush(HP* hp, HPDataType x)
{
	assert(hp);
	if (hp->size == hp->capacity)
	{
		size_t newCapacity = hp->capacity == 0 ? 4 : hp->capacity * 2;
		HPDataType* tmp = realloc(hp->a, sizeof(HPDataType)*newCapacity);
		if (tmp == NULL)
		{
			printf("realloc fail\n");
			exit(-1);
		}

		hp->a = tmp;
		hp->capacity = newCapacity;
	}

	hp->a[hp->size] = x;
	hp->size++;
	AdjustUp(hp->a, hp->size - 1);
}

4. HeapPop

删除根节点,并且调整堆的数据(根据大/小堆选择向上/向下调整) 使堆保持原来的性质

void HeapPop(HP* hp)
{
	assert(hp);
	assert(!HeapEmpty(hp));
	swap(&hp->a[0], &hp->a[hp->size - 1]);
	hp->size--;

	AdjustDown(hp->a, hp->size, 0);
}

5. HeapEmpty

检查堆是否为空

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

6.AdjustUp

向上调整,将插入的数据从最底部向上调整 ,维持堆的性质不变

void AdjustUp(int* a, int child)
{
	assert(a);

	int parent = (child - 1) >>1;
	//while (parent >= 0)
	while (child > 0)
	{
		if (a[child] > a[parent])
		{
			swap(&a[child], &a[parent]);

			child = parent;
			parent = (child - 1) / 2;
		}
		else       break;
	}
}

7. AdjustDown

向下调整,将插入的数据从根节点向下调整 , 维持堆的性质不变

void AdjustDown(int* a, int n, int parent)//删除堆顶的数据  删除根节点  筛选最值
{
	int  child = parent * 2 + 1;//只用左孩子   右孩子的下标 是左孩子 + 1
	while (child < n)
	{
		//选出较小的那个孩子            判断右孩子是否越界
		if (a[child + 1] < a[child] && child + 1 < n)	child++;

		//如果小的孩子小于父亲  就继续调整
		if (a[child] < a[parent])
		{
			swap(&a[parent], &a[child]);
			parent = child;
			child = parent * 2 + 1;
		}
		else				break;//如果不符合条件就 break 
	}
}

8. HeapSize

返回堆的节点数

int HeapSize(HP* hp)
{
	assert(hp);
	return hp->size;
}

9. HeapTop

返回根节点顶元素大小

HPDataType HeapTop(HP* hp)
{
	assert(hp);
	assert(!HeapEmpty(hp));

	return hp->a[0];
}

10. HeapPrint

打印堆(线性 数组)

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

实现细节

  1. 根据AdjustUp / AdjustDown中的> /<来判断是 大根堆/小跟堆 调整

例如:image-20220206110519179

2.AdjustUpwhile循环的判断条件一般是 child > 0
3. AdjustDownwhile 循环的条件 一般是 child < n

  • 17
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 14
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值