用C语言实现堆以及性质

本文介绍了如何使用C语言实现堆,包括向下调整算法、创建堆、堆的时间复杂度分析、堆的插入和删除操作。堆分为大堆和小堆,通过调整算法确保其性质。在创建堆时,从倒数的第一个非叶子节点开始调整直至根节点。堆的插入和删除过程中,分别进行了向上调整和向下调整以保持堆的性质。时间复杂度为O(N)。
摘要由CSDN通过智能技术生成

堆的实现

下面我们给出一个数组,这个数组逻辑上可以看做一颗完全二叉树,但是还不是一个堆,现在我们通过算法,把它构建成一个堆。根节点左右子树不是堆,我们怎么调整呢?这里我们从倒数的第一个非叶子节点的 子树开始调整,一直调整到根节点的树,就可以调整成堆。

堆分为大堆和小堆

大堆:每个父亲节点都比孩子节点大;

小堆:每个父亲节点都比孩子节点小;

向下调整

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

例如:

int array[] = {27,15,19,18,28,34,65,49,25,37};

 

 同理第一个交换完成后,接着比较现在的孩子节点与根节点的大小关系,直到父亲节点都小于孩子节点,或者父亲节点没有孩子节点的情况下结束;

同理建大堆向下调整;

//向下调整
void AdjustDown(int* 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 AdjustUp(int* a, int child)
{
	assert(a);

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

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

创建堆 

 从倒数的第一个非叶子节点的 子树开始向下调整,一直调整到根节点的树,就可以调整成堆。

例如:(建大堆)

int a[] = {1,5,3,8,7,6};

 

建立过程如下: 

 

 

 堆的时间复杂度

 所以时间复杂度为O(N);

堆的插入

把一个数先插入一个数组的尾上,再进行向上调整算法,直到满足堆。

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);
}

 

堆的删除

删除堆是删除堆顶的数据,将堆顶的数据根据最后一个数据交换,然后删除数组最后一个数据,再向下调整算法;

 

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);
}

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值