堆排序(二)——排序

堆排序有两个侧重点,一个是 “堆”,一个是“排序”

1、“堆”——建小堆

2、“排序”——将堆顶元素和堆底的最后一个元素交换,除了堆底最后一个元素外,调整剩下的元素

建小堆在前一篇博客中已经完成了

堆排序——建小堆_challenglistic的博客-CSDN博客堆排序有两个侧重点,一个是 “堆”,一个是“排序”1、“堆”——建小堆2、“排序”——将堆顶元素和堆底的最后一个元素交换,除了堆底最后一个元素外,调整剩下的元素一、提出问题假设现在有一个无序的数组int arr[] = { 70,56,30,24,33,10,75,68,90,21};现在要在不额外开辟空间的情况下,将这个数组转化为堆二、思路分析1、画二叉树堆在物理实现上使用的是顺序容器,但是在逻辑分析中使用的是二叉树所以我们的第一步是将改数组 画 成二叉树https://blog.csdn.net/challenglistic/article/details/123285800?spm=1001.2014.3001.5501

接下来将在前面的基础上 进行排序


目录

一、提出问题

二、思路分析

1、画二叉树

 2、将堆顶元素和堆底的最后一个元素互换

3、准备下一轮调整

三、代码实现

四、测试

五、时间复杂度


一、提出问题

现在有一个 小堆数组,在不额外开辟空间的情况下,得到一个从小到大排列的有序数组

二、思路分析

1、画二叉树

我们将数组画成二叉树的形式来分析

 2、将堆顶元素和堆底的最后一个元素互换

这样做的目的是,将已经得到的最小数放到最后,除了最小数外,剩下的数重新调整

绿色圈中,根元素的左子树 和 右子树 都是标准的小堆,所以我们没有必要像 建堆 一样,从底部的子树开始调整,我们只需要从根部向下调整即可

3、准备下一轮调整

end前移,树的节点数size要减少一个,因为end 后面的节点都是每一轮选出来的最小数

三、代码实现

我们以最初的为例,

(1)先把第一个元素和最后一个元素交换

(2)然后需要调整的节点个数size 减一

(3)从根部向下调整

(4)树的尾部 end 向前移动,end 减一

void HeapSort(int* a,int size)
{
	CreateHeap(a, size);


	int end = size - 1;
	while (end>0)
	{
		//将堆顶元素和堆底元素互换
		Swap(a[0], a[end]);
		//交换以后,最小的数放在堆底,要参加堆调整的节点个数要减一
		size--;

		//由于子树都是小堆,直接从堆顶向下调整
		AdjustDown(a, 0, size);

		//每得到一个最小的,都会被放到最后,最后一个节点的位置向前移动
		end--;
	}
}

四、测试

int main() {
	int arr[] = { 70,56,30,24,33,10,75,68,90,21};
	HeapSort(arr, sizeof(arr) / sizeof(arr[0]));

	for (size_t i = sizeof(arr) / sizeof(arr[0])-1; i > 0 ; i--)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
	return 0;
}

五、时间复杂度

建小堆的时间复杂度:O(N)

每次从根部调整的时间复杂度:O(log N)

需要调整 N-K次

所以时间复杂度是 O(N)+O((N-1)*log N) ≈ O(Nlog N)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值