数据结构初阶 堆(二)

一. 堆的接口函数(续)

虽然我们的上一篇博客已经写过了堆的前面一些接口函数

这里我们再重复一遍

1. 结构体形式

我们这里形式上使用一个数组来表示一个逻辑上的二叉树

typedef int HPDateType;

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

2. 初始化和销毁

这里的两个接口函数都很简单 我们直接连起来动手实现一下

初始化

void HeapInit(HP* php)
{
	assert(php);
	php->a = (HPDateType*)malloc(sizeof(HPDateType) * 4);
	if (php->a == NULL)
	{
		perror("malloc fail");
		return;
	}
	php->size =0;
	php->capacity = 4;
}

销毁

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

3. 添加数据(小堆为例)

当我们这里插入一个10的时候 这里明显是错误的啊 怎么办呢?

这个时候我们就需要将它跟它的父亲比较 是否小于它的父亲

如果不小于就填入

如果大于就交换它和它的父亲

知道孩子等于0为止

下面开始写代码

void HeapPush(HP* php, HPDateType x)
{
	assert(php);
	if (php->size == php->capacity)
	{
		HPDateType* tmp = (HPDateType*)realloc(php->a,sizeof(HPDateType) * php->capacity * 2);
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}
		php->a = tmp;
		php->capacity *= 2;
	}
	php->a[php->size] = x;
	php->size++;
	AdJustUp(php->a, php->size - 1);
}

这里因为判断是否需要调整这个函数要使用很多次

所以说我们单独写出一个函数出来

void Swap(HPDateType* p1, HPDateType* p2)
{
	HPDateType x = *p1;
	*p1 = *p2;
	*p2 = x;
}
//除child这个位置,前面数据构成堆
//向上调整
void AdJustUp(HPDateType* a, int child)
{
	int parent = (child - 1) / 2;
	while (child > 0)
	{
		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);
			child = parent;
			//更新父亲的位置
			parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}

 整体代码如下

void Swap(HPDateType* p1, HPDateType* p2)
{
	HPDateType x = *p1;
	*p1 = *p2;
	*p2 = x;
}
//除child这个位置,前面数据构成堆
//向上调整
void AdJustUp(HPDateType* a, int child)
{
	int parent = (child - 1) / 2;
	while (child > 0)
	{
		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);
			child = parent;
			//更新父亲的位置
			parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}

void HeapPush(HP* php, HPDateType x)
{
	assert(php);
	if (php->size == php->capacity)
	{
		HPDateType* tmp = (HPDateType*)realloc(php->a,sizeof(HPDateType) * php->capacity * 2);
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}
		php->a = tmp;
		php->capacity *= 2;
	}
	php->a[php->size] = x;
	php->size++;
	AdJustUp(php->a, php->size - 1);
}

4. 删除数据

 

我们想要删除堆中的一个数据 还要不改变这个堆的结构 这个时候怎么办呢

这个时候我们这里给出一种很巧妙的解法

我们先将最前面的元素和最后面的元素交换位置

然后再删除掉堆最后面的元素

之后开始向下调整这个堆

如上图所示

下面是删除数据的大体逻辑

void HeapPop(HP* php)
{
	assert(php);
	assert(!HeapEmpty(&php));
	//删除数据
	Swap(&php->a[0], &php->a[php->size - 1]);
	php->size--;

这里我们还需要再写一个函数向下调整

void AdJustDown(HPDateType* a, int n, int parent)
{
	int child = parent * 2 + 1;
	while(child < n)
	{
		//选出左右孩子中大的那一个
		//需要先判断右孩子是否存在防止出现越界问题
		if (child + 1<n && a[child + 1] > a[child])
		{
			child++;
		}
		if (a[child] > a[parent])
		{
			Swap(&a[child], &a[parent]);
			parent = child;
			//更新孩子的位置
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

调整函数如上

我们再来整体看看这个函数

void AdJustDown(HPDateType* a, int n, int parent)
{
	int child = parent * 2 + 1;
	while(child < n)
	{
		//选出左右孩子中大的那一个
		//需要先判断右孩子是否存在防止出现越界问题
		if (child + 1<n && a[child + 1] > a[child])
		{
			child++;
		}
		if (a[child] > a[parent])
		{
			Swap(&a[child], &a[parent]);
			parent = child;
			//更新孩子的位置
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}
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);
}

测试一下试试

5. 返回大小 

这个很简单 返回size大小

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

7. 判断为空

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

8.返回堆顶数据

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

以上便是本文所有内容了,如有错误请各位大佬不吝赐教,感谢留言

  • 15
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值