堆排序

堆排序介绍

我们知道,堆分为"最大堆"和"最小堆"。最大堆通常被用来进行"升序"排序,而最小堆通常被用来进行"降序"排序。鉴于最大堆和最小堆是对称关系,理解其中一种即可。本文将对最大堆实现的升序排序进行详细说明。

最大堆进行升序排序的基本思想:

  1. 初始化堆:将数列a[0…n-1]构造成最大堆。
  2. 交换数据:将a[0]和a[n-1]交换,使a[n]是a[0…n-1]中的最大值;然后将a[0…n-2]重新调整为最大堆。 接着,将a[0]和a[n-2]交换,使a[n-2]是a[0…n-2]中的最大值;然后将a[0…n-3]重新调整为最大值。 依次类推,直到整个数列都是有序的。

堆排序图文说明

1、初始化堆

基本思想:假设存在n个数据的无序数组a[0…n-1],其左右子节点对于父节点i的索引分别是2 * i+1和2 * i+2,则最后一个父节点的索引为(n-1)/2,以此父节点为基准,采用堆的向下调整算法,从后往前遍历,这样就可以将无序数组转化为二叉堆。

for (int i = size / 2-1; i >= 0; i--)
{
	maxHeapDown(vec, i, size - 1);		//最大堆的向下调整算法
}

详细图文介绍见参考链接

2、交换数据

在将数组转换成最大堆之后,接着要进行交换数据,从而使数组成为一个真正的有序数组。
在这里插入图片描述
上面是当n=10时,交换数据的示意图。
当n=10时,首先交换a[0]和a[10],使得a[10]是a[0…10]之间的最大值;然后,调整a[0…9]使它称为最大堆。交换之后:a[10]是有序的!
当n=9时, 首先交换a[0]和a[9],使得a[9]是a[0…9]之间的最大值;然后,调整a[0…8]使它称为最大堆。交换之后:a[9…10]是有序的!

依此类推,直到a[0…10]是有序的。

堆排序实现

void maxHeapDown(vector<int> &vec, int start, int end) 	//堆的向下调整算法
{
	if (vec.size() == 0) return;
	int cur = start;
	int lch = 2 * start + 1;
	int tmp = vec[cur];
	while (lch <= end)
	{
		if (lch < end && vec[lch] < vec[lch + 1])
		{
			lch++;
		}
		if (tmp >= vec[lch])
			break;
		vec[cur] = vec[lch];
		cur = lch;
		lch = 2 * cur + 1;
	}
	vec[cur] = tmp;
}

void maxHeapSort(vector<int> &vec)		//堆排序
{
	if (vec.size() == 0) return;
	int size = vec.size();
	for (int i = size / 2-1; i >= 0; i--)		//初始化堆
	{
		maxHeapDown(vec, i, size - 1);
	}
	for (int i = size - 1; i > 0; i--)
	{
		swap(vec[0], vec[i]);			//交换数据
		maxHeapDown(vec, 0, i - 1);		//剩余部分调整成最大堆
	}
}

void maxHeapSortTest()		//测试用例
{
	vector<int> vec = { 7, 4, 4, 3, 1, 18, 6, 1, 5 };
	maxHeapSort(vec);
	for (int i = 0; i < vec.size(); i++)
	{
		cout << vec[i] << " ";
	}
	cout << endl;
}

时间复杂度和稳定性

时间复杂度

堆排序的时间复杂度是O(NlgN)。
假设被排序的数列中有N个数。遍历一趟的时间复杂度是O(N),需要遍历多少次呢?
堆排序是采用的二叉堆进行排序的,二叉堆就是一棵二叉树,它需要遍历的次数就是二叉树的深度,而根据完全二叉树的定义,它的深度至少是lg(N+1)。最多是多少呢?由于二叉堆是完全二叉树,因此,它的深度最多也不会超过lg(2N)。因此,遍历一趟的时间复杂度是O(N),而遍历次数介于lg(N+1)和lg(2N)之间;因此得出它的时间复杂度是O(NlgN)。

稳定性

堆排序是不稳定的算法。

原文链接如下:https://www.cnblogs.com/skywang12345/p/3602162.html#a42

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值