堆(数据结构)的基本操作

本文介绍了堆这一数据结构的基础知识,重点讨论了其核心操作,包括插入元素、删除最大(最小)元素以及如何维护堆的性质。通过学习,读者将能够掌握堆的基本操作并理解其在优先队列和排序中的应用。

堆(数据结构)的基本操作

堆是数据结构的一种,表现形式经常是数组来表示,我们经常将其看作完全二叉树,第一层是第一个数据,第二层是第二个和第三个数据以此类推。堆的好处是当数据很多时方便查找,一个大堆的堆顶一定是最大值,堆顶冒掉后只需要log n复杂度就可以选出第二大的数据,当数据有上亿时很方便查找。

以下为堆的实现代码。
typedef int HeapDateType;

typedef struct Heap
{
	HeapDateType* _a;
	size_t _size;
	size_t _capacity;//容量
}Heap;
初始化堆
void HeapInit(Heap* hp, HeapDateType* a, size_t n)
{
	hp->_a = (HeapDateType*)malloc(sizeof(HeapDateType)*n);
	int i = 0;
	for (;i < n;i++)
	{
		hp->_a[i] = *a;
		a++;
	}
	hp->_size = n;
}
容量扩充
void HeapDilatation(Heap* hp)
{
	if (hp->_size == hp->_capacity)
	{
		(Heap*)realloc(hp,hp->_capacity*sizeof(Heap));
	}
}
给一个交换两个数的函数,方便后面的向上向下调整算法。
void Swap( HeapDateType* a, HeapDateType* b)
{
	HeapDateType c=0;
	c = *b;
	*b = *a;
	*a = c;
}
大堆向下调整,先让parents指向父亲节点,child指向左孩子节点,判断如果有右孩子节点并且右孩子节点大于左孩子节点,那么让child++指向右孩子节点。接下来判断父亲节点是否小于孩子节点,如果小于的话交换父亲节点与孩子节点。这样可以保证在父亲节点一定大于孩子节点。再将孩子节点给到父亲节点,在进行以上操作直到叶子节点为止。
void HeapBigAdjustDown(Heap* hp,size_t x)
{//大堆向下调整
	int parents = x;
	int child = parents * 2 + 1;
	while (child < hp->_size)
	{
		if (child+1 < hp->_size && (hp->_a[child] < hp->_a[child + 1]))
		{
			++child;
		}
		if (hp->_a[parents] < hp->_a[child])
		{
			Swap(&(hp->_a[parents]),&(hp->_a[child]));
			parents = child;
			child = parents * 2 + 1;
		}
		else
		{
			break;
		}
	}
}
小堆向下调整,将选定的节点所存的数据一直向下调整,原理同上。
void HeapSmallAdjustDown(Heap* hp, size_t x)
{//小堆向下调整
	int parents = x;
	int child = parents * 2 + 1;
	while (child < hp->_size)
	{
		if (child+1 < hp->_size && (hp->_a[child] > hp->_a[child + 1]))
		{
			++child;
		}
		if (hp->_a[parents] > hp->_a[child])
		{
			Swap(&(hp->_a[parents]), &(hp->_a[child]));
			parents = child;
			child = parents * 2 + 1;
		}
		else
		{
			break;
		}
	}
}
小堆向上调整。给定child参数,用child参数得到parents数据。判断如果child大于parents的话将两个数据交换。并且将parents的数据给child,直到调整到根节点或者child小于parents结束。以下为实现代码。
void HeapSmallAdjustUp(Heap* hp, int child)
{//小堆向上调整
	int parents = (child - 1) / 2;
	while (child != 0)
	{
		if (hp->_a[child] < hp->_a[parents])
		{
			Swap(&(hp->_a[child]), &(hp->_a[parents]));
			child = parents;
			parents = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}
大堆向上调整,算法原理同上。
void HeapBigAdjustUp(Heap* hp, int child)
{//大堆向上调整
	int parents = (child - 1) / 2;
	while (child != 0)
	{
		if (hp->_a[child] > hp->_a[parents])
		{
			Swap(&(hp->_a[child]), &(hp->_a[parents]));
			child = parents;
			parents = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}
建一个大堆。从最后一个非叶子节点开始向下调整到根节点即可。调整最后一个非叶子节点保证从最后开始每一次的左子树与右子树都是大堆,一直调到根节点的时候,根节点左子树与右子树都是大堆,只需要调整根节点即可。
void MakeBigHeap(Heap* hp)
{
	int i = (hp->_size-2)/2;
	for (;i >= 0;i--)
	{
		HeapBigAdjustDown(hp,i);
	}
}
建一个小堆。原理同上。
void MakeSmallHeap(Heap* hp)
{
	int i = (hp->_size - 2) / 2;
	for (;i >= 0;i--)
	{
		HeapSmallAdjustDown(hp, i);
	}
}
插入一个数据,在尾巴插入一个数据,将这个数据进行向上调整即可。
void HeapPush(Heap* hp, HeapDateType x)
{
	hp->_a[hp->_size] = x;
	HeapSmallAdjustUp(hp,hp->_size);
	hp->_size += 1;
}
删除一个数据。将堆顶数据与最后一个数据交换,将size--并且将交换后的根节点向下调整即可。
void HeapPop(Heap* hp)
{
	Swap(&hp->_a[0], &hp->_a[hp->_size - 1]);
	hp->_size--;
	HeapSmallAdjustDown(hp, 0);
}
堆内存储的数据个数。直接返回size即可。
size_t HeapSize(Heap* hp)
 {
	return hp->_size;
}
堆判空,如果size等于0的话那么为空堆返回0,反之返回1
size_t HeapEmpty(Heap* hp)
{
	if (hp->_size == 0)
	{
		return 0;
	}
	else
	{
		return 1;
	}
}
取堆顶元素
HeapDateType HeapTop(Heap* hp)
{
	return hp->_a[0];
}

堆排序(降序)。将堆顶元素(最小元素)与最后一个元素交换,然后size--,堆顶元素进行向下调整选出当前最小元素再次交换,直到到最后一个元素为止。
void HeapSort(Heap* hp,size_t n)
{//降序
	while (hp->_size)
	{
		Swap(&(hp->_a[0]),&(hp->_a[hp->_size-1]));
		hp->_size-=1;
		HeapSmallAdjustDown(hp,0);
	}
	hp->_size = n;
}
打印堆
void HeapPrint(Heap* hp)
{
	Heap* ptr = hp;
	int i = 0;
	for (;i < hp->_size;i++)
	{
		printf("%d  ",hp->_a[i]);
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值