4、堆排序

堆排序是利用二叉树数据结构设计的一种排序算法。

需要注意的是排升序要建大堆,排降序建小堆。

为什么要这样建堆呢?

在初学堆排序时,按照我们自己对二叉树的理解,正常认为,升序建小堆,降序建大堆,但是这是错误的,在解释这个错误之前,我们先了解一下堆排序的思想

思路

堆排序是先要建堆,用向下调整建堆,然后根和最后的叶子结点相交换,交换后,将最后元素固定,使用向下调整选出次大的元素,反复操作。

如图是排降序建小堆的过程

 

 

 向下调整建堆

 向下调整建堆是指根与下面的子节点比较数值交换至适合位置,向下调整建堆的前提是(以小堆为例):根的左子树,右子树都是小堆,这就需要先调整左右子树,而调整左右子树的前提是以左右子树为根的左右子树都是小堆,依次类推,直到叶子节点

先调整粉框树再调整红框树最后调整整个树

 

//向下调整
void DownHeap(Heap* hp,int n,int i)
{
	int parent = i;
	int child = parent * 2 + 1;
	
	while(child<n)
	{
		if (child + 1 < n && hp->_a[child] > hp->_a[child + 1])
		{
			child++;
		}
		if (hp->_a[child] < hp->_a[parent])
		{
			int tmp = hp->_a[child];
			hp->_a[child] = hp->_a[parent];
			hp->_a[parent] = tmp;
		}
		else
		{
			break;
		}
		parent = child;
		child = parent * 2 + 1;
	}
}
void HeapSort(Heap* hp, int n)
{
	//向下调整建堆                        //倒着向下建堆;
	for (int i =(n-1-1)/2; i >= 0; i--)  //n-1表示数组最后一个元素;
	{                                    //(n-1-1)/2是表示叶子节点的父节点;
		DownHeap(hp, n, i);              //子节点和父节点的关系是:parent = (child-1)/2;
	}
}
 纠错

如果升序建小堆,降序建大堆,(小堆升序为例),选出最小的数据后,排在根的位置,之后剩下的数据需要再看做堆,这样父子关系全乱了,都需要重新建新的堆,代价太大!!!

找到了最小值1,排入根的位置

 

父子关系全乱,需要重新建堆(这个例子已是升序,只是巧合!)

继续

建立堆后,我们已经得到最小的数在根处,之后要和最后的叶子节点交换位置,再向下调整找出次小的数移至根处,向下调整时,把之前最小的数忽视掉,那个数现在的位置已经是他的最终位置,不需要再动

int end = n - 1;
	while (end > 0)
	{
		int tmp = hp->_a[end];
		hp->_a[end] = hp->_a[0];
		hp->_a[0] = tmp;

		DownHeap(hp,end,0);
		end--;                    //控制与根交换后的最小数不参与调整
	}
 代码
void DownHeap(Heap* hp,int n,int i)
{
	int parent = i;
	int child = parent * 2 + 1;
	
	while(child<n)
	{
		if (child + 1 < n && hp->_a[child] > hp->_a[child + 1])
		{
			child++;
		}
		if (hp->_a[child] < hp->_a[parent])
		{
			int tmp = hp->_a[child];
			hp->_a[child] = hp->_a[parent];
			hp->_a[parent] = tmp;
		}
		else
		{
			break;
		}
		parent = child;
		child = parent * 2 + 1;
	}
}
void HeapSort(Heap* hp, int n)
{
	//建堆
	for (int i =(n-1-1)/2; i >= 0; i--)
	{
		DownHeap(hp, n, i);
	}
	int end = n - 1;
	while (end > 0)
	{
		int tmp = hp->_a[end];
		hp->_a[end] = hp->_a[0];
		hp->_a[0] = tmp;

		DownHeap(hp,end,0);
		end--;
	}
}

时间复杂度:O(nlogn)

空间复杂度:O(1) 

稳定性:不稳定

 

 

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值