什么是堆?

堆使用数组表示的完全二叉树,并且其结点大于或小于其子节点。
大于是大堆,小于是小堆。


堆的操作有哪些

堆的初始化

我建立了一个堆结点hp,这样在后面调用堆操作函数中方便调用,这个结点中包括了堆(就是数组)的指针a,堆(就是数组)的大小capacity,以及堆(就是数组)下标size

#include<stdio.h>
#include<assert.h>
#include<malloc.h>

typedef int HPDataType;

typedef struct Heap
{
	HPDataType* a;
	int size;
	int capacity;
}Heap;

void HeapInit(Heap* hp, HPDataType* a, int n)//初始化,n是要构建的堆大小,即数组a的大小
{
	assert(hp);
	hp->a = a;//将构建堆的数组传递到堆指针中
	hp->capacity = n;
	hp->size = 0;
}

堆的建立

这里建一个小堆为例子。
小堆的特点就是整棵树中最小的结点在堆顶,并且父节点总大于等于子结点。
1、从最后一个父亲结点开始,自底向上交换结点,那么最小的结点自然就会交换到堆顶。可以看下面动图更方便的理解。
在这里插入图片描述因此这里写了一个大结点向下调整的函数

void AdjustDown(HPDataType* a, int size, int n)//size是堆大小,n是下标
{
	assert(a);
	int parent = n;//传进来的结点下标一定是父节点
	int child = 2 * parent + 1;//左孩子
	while (child < size)//当判断到叶子结点为止
	{
		if (parent * 2 + 2 == size)//判断有无右节点
			child = 2 * parent + 1;
		else
			child = (a[2 * parent + 1] < a[2 * parent + 2] ?
			 2 * parent + 1 : 2 * parent + 2);//取较小的孩子和父结点交换
		if (a[parent] > a[child])//构建小堆
		{
			Swap(&a[parent], &a[child]);//交换较小孩子和夫结点
			parent = child;
			child = parent * 2 + 1;
		}
		else
			break;//左右孩子都比夫结点大就停止
	}
}

建堆函数,从最后一个夫结点开始向下调整,将大结点都调整到下面

void CreatLiHeap(HPDataType* a, int size)//建小堆
{
	for (int i = size / 2 - 1; i >= 0; i--)
	{
		AdjustDown_L(a, size, i);//向下调整,n是下标
	}
}

堆插入结点

对于堆后面插入一个结点

  1. 要判断空间是否足够,不够则扩容。
  2. 对于插入的结点进行向上调整向上调整就是,如果插入的结点比他的父结点要小,就要把他调整到上面。
    向上调整函数
void AdjustUp_L(HPDataType* a, int n)//向上调整,用来建小堆
{
	assert(a);
	int child = n;
	int parent = (n - 1) / 2;//得到其父结点下标
	while (child > 0)
	{
		if (a[parent] <= a[child])
			break;//知道比其父节点小则停止
		else
		{
			Swap(&a[parent], &a[child]);
			child = parent;
			parent = (child - 1) / 2;
		}
	}
}

插入函数

void HeapPush(Heap* hp, HPDataType x)//后插 
{
	assert(hp);
	if (HeapFull(hp))//判满函数,满的话重新开辟空间
	{
		int newspace = hp->capacity * 2;
		hp->a = (HPDataType*)realloc(hp->a, sizeof(HPDataType)*newspace);
		hp->capacity = newspace;
	}
	hp->a[hp->size] = x;
	hp->size++;
	AdjustUp_L(hp->a, hp->size - 1);//向上调整
}

堆排序

如果我们了解堆的特性,就知道他的堆顶总是最小(大)值,并且将一个数组构建乘一个堆的时间复杂度为o(logN)。比遍历一个数组找到一个最小(大)时间复杂度o(n)效率高得多,因此就有了堆排序。

void HeapSort(int* a, int size)//堆排序//升序
{
	//1、先建一个大堆(升序建立大堆)
	for (int i = size / 2 - 1; i >= 0; i--)
	{
		AdjustDown(a, size, i);//向下调整,size是数组大小i是下标
	}
	int end = size - 1;//end是最后一个结点的数组下标
	//2、每次令堆顶和堆尾元素交换
 	while (end>0)
	{
		Swap(&a[0], &a[end]);
		//3、向下调整,改变数组范围
		AdjustDown(a, end, 0);
		end--;
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值