数据结构之堆

1、堆的概念及结构

 大堆:树中一个树及子树中,任何一个父亲都大于等于孩子。

小堆:树中一个树及子树中,任何一个父亲都小于等于孩子。

堆的作用:

1、堆排序。

2、TopK问题。在N隔数种,找出最大或者最小的的前K个数。

堆的逻辑结构:完全二叉树

堆的物理结构:数组。

父亲和孩子的关系:parent=(child-1)/2;

2、堆的实现:

因为堆的实际存储结构是数组,所以堆得实现类似于顺序表,这里不再详细介绍,重点介绍一下堆的插入和删除。

1、堆的插入

假设我们要实现的是大堆,即每一个父亲节点都大于孩子节点。

假设有一个现成的堆,准备插入一个数据。

 先通过孩子节点的下标算出父亲的下标,接着比较大小,当孩子大于父亲时,就要交换孩子与父亲的值,然后继续比较,直到孩子小于父亲。所以该过程放在while循环中进行,当孩子为根时,或者孩子小于父亲时,循环停止。

这里要注意,如果以父亲的坐标为停止循环的条件,那么父亲是一直大于0的,导致程序没有从正缺的方向走出去。

2、堆的删除

堆的删除不是直接删除数据的最后一个,而是要删除最大或者最小的那一个,也就是堆顶的数据。

但是不能破坏堆原有的结构。

步骤:

1、先将堆顶元素与最后一个元素进行交换。

2、删除堆中最后一个元素。

3、将堆顶元素向下调整直到满足堆的特性。

向下调整步骤:

跟左右孩子中最小的孩子交换。

结束条件:父亲小于等于孩子或者调整到最后,即成为叶子节点。

 调整后:

 

 

附:堆实现的代码

typedef  int HeapDataType;

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

void HeapInit(HP* hp);

void HeapDestroy(HP* hp);

void HeapPush(HP* hp, HeapDataType x);

void Swap(HeapDataType* px, HeapDataType* py);

void HeapPop(HP* hp);

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

void HeapDestroy(HP* hp)
{
	assert(hp);
	free(hp->a);
	hp->capacity = 0;
	hp->size = 0;
}
void Swap(HeapDataType* px, HeapDataType* py)
{
	HeapDataType temp = *px;
	*px = *py;
	*py = temp;
}
void Adjust(HeapDataType* a, int childl) //走的大堆
{
	int parent = (childl - 1) / 2;
	while (childl>0)
	{
		if (a[childl] < a[parent])
		{
			Swap(&a[childl], &a[parent]);
			childl = parent;
			parent = (childl - 1) / 2;
		}
		else
		{
			break;
		}
	}
}
void HeapPush(HP* hp, HeapDataType x)
{
	assert(hp);
	if (hp->capacity == hp->size)
	{
		int newcapacity = hp->capacity == 0 ? 4 : 2 * hp->capacity;
		HeapDataType* temp = (HeapDataType*)realloc(hp->a,sizeof(HeapDataType) * newcapacity);
		if (temp == NULL)
		{
			printf("realloc is fail");
			exit(-1);
		}
		hp->a = temp;
		hp->capacity = newcapacity;
	}
	hp->a[hp->size]=x;
	Adjust(hp->a, hp->size);
	hp->size++;

}

void AdjustDown(int* a, int size, int parent)  //调得小堆
{

	int child = 2 * parent + 1;

	while (child < size)
	{
		//先找孩子中最小的那一个
		if (child+1<size &&  a[child + 1]< a[child])//因为这个地方child+1可能不存在
		{
			child++;
		}
		if (  a[child]< a[parent])
		{
			Swap(&a[parent], &a[child]);
			parent = child;
			child = 2 * parent + 1;
		}
		else
		{
			break;
		}
	}
}
//删除堆顶的数据 
void HeapPop(HP* hp)
{
	assert(hp);
	assert(!HeapEmpty(hp));
	Swap(&hp->a[hp->size-1], &hp->a[0]);
	hp->size--;
	AdjustDown(hp->a, hp->size, 0);
}

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

开拓的嚣张

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值