【针对性复习】堆的创建、调整、排序

针对选择题中二叉树顺序结构堆的复习

堆的概念:

堆是一棵完全二叉树,堆中的元素存储到一维数组中,对于任意节点,如果该节点小于(大于)其左右孩子,就是小(大)堆

堆的特性:

<1>.堆顶元素一定是堆中所有元素最大的(最小的)
<2>.从根节点到任意一条支路的最后一个节点都是一个有序的序列,如果是小堆,就是升序,如果是大堆,就是降序

堆的创建:

堆中的元素是储存在一维数组中的,所以先提供一个数组,完成堆的初始化

初始化:

void InitHeap(Heap* hp, HpDataType* array, int size, Compare compare)
{
	assert(hp);

	try
	{
		hp->_array = new HpDataType[size];
	}
	catch (...)
	{
		cout << "申请空间错误!" << endl;
	}

	hp->_capacity = size;

	for (int i = 0; i < size; ++i)
	{
		hp->_array[i] = array[i];
	}

	hp->_size = size;
}

调整:

通过刚才的代码,我们把堆初始化好了,但是还不满足堆的性质,所以我们还需要进一步调整

向下调整:

向下调整算法有一个前提:左右子树必须是一个堆,才能调整
在这里插入图片描述
针对比较随机的数组,改进向下调整算法,int array[] = { 2, 3, 8, 0, 9, 1, 7, 4, 6, 5 };

如果根节点的左右子树不满足堆的性质,我们从倒数第一个叶子节点开始向下调整

这样把最后一组根节点和子树都处理完毕,然后处理上一个叶子节点,直到处理到根节点

代码如下:

	//空间申请完毕,数据拷贝完毕,开始调整,满足堆的性质
	int lastleaf = (size - 2) >> 1;

	while (lastleaf >= 0)
	{
		AdjustDown(hp->_array, hp->_size, lastleaf, hp->compare);
		lastleaf--;
	}
向上调整:

堆的向上调整主要是用在插入元素,插入元素只会影响到它的双亲

所以将插入元素一直与双亲比较,一直比较到满足堆序或者到根节点

在这里插入图片描述

代码如下:

void AdjustUp(HPDataType* a, int size, int child,PCom compare)
{
	int parent = (child - 1) / 2;

	while (child != 0)
	{
		if (compare(a[child] , a[parent]))
		{
			swap(&a[child], &a[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			return;
		}
	}
}

排序:

有了前面的向上和向下排序,那么堆排就可以实现了

方法是先将数组中的元素构建成堆,向下调整为大堆,首尾交换,头部最大的元素就跑到最后的位置

然后元素个数自减,再把剩下的元素调成大堆,直到没有可以调的,就完成了排序(降序)

int array[] = { 2, 3, 8, 0, 9, 1, 7, 4, 6, 5 };
在这里插入图片描述
代码如下:

void HeapAdjust(int* array, int size, int parent)
{
	int child = parent * 2 + 1;

	while (child < size)
	{
		if (child + 1 < size && array[child + 1] > array[child])
			child += 1;

		if (array[child] > array[parent])
		{
			swap(array[child], array[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			return;
		}
	}
}

void HeapSort(int* array, int size)
{
	int root = ((size - 2) >> 1);
	for (root; root >= 0; --root)
	{
		HeapAdjust(array, size, root);
	}


	int end = size - 1;
	while (end != 0)
	{
		swap(array[0], array[end]);
		HeapAdjust(array, end, 0);
		end--;
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值