数据结构—堆排序

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/z_x_m_m_q/article/details/82413667

堆排序

堆排是基于堆的一种排序算法,对于堆的了解请点开链接:https://blog.csdn.net/z_x_m_m_q/article/details/82320357(创建、插入、删除) 

算法思想:

之前的博客写了小堆,由于降序排列是根据小堆性质进行排列的,顺着前面的知识这里我们讨论从大到小的排列

首先小堆建好之后堆顶数据是堆中最小的数据,将堆顶元素与最后的一个元素交换位置,这样最后元素就出在有序区间了。再对除有序区间外的其他数据从堆顶开始来一次向下调整,这样堆顶数据又是堆中最小的数据,重复上述步骤直至堆中只剩下一个元素。

以具有N个数据的数组 a[N] 为例,说下对排序的步骤:

  1. 利用数组中元素建立节点量为 N 的小堆
  2. 第一次将a[0] 与 a[N-1]交换位置,对a[0]至a[N-2]进行一次向下调整,重新恢复成小堆(此时堆的节点量为N-1)
  3. 第二次将a[0] 与 a[N-2]交换位置,对a[0] 至 a[N-3]进行一次向下调整,重新恢复成小堆(此时堆的节点量变为n-2)
  4. 重复这样的操作,直至 a[0] 与 a[1]交换

图形分析:

这样一直下去,就好了。。。

算法代码:

这里我只写了核心代码: 

void HeapSort(int* a,int n)
{
	int i = 0;

	//建小堆
	for (i = (n-2)/2;i >= 0;--i)
		HeapAdjustDown(a, n, i);

	//交换堆顶、堆尾数据
	for (i = n-1;i > 0;--i)
	{
		Swap(&a[0],&a[i]);
		HeapAdjustDown(a, i, 0);  //每次从堆顶开始向下调整,i 刚好是新堆的节点数
	}
}

时间复杂度和空间复杂度:

时间复杂度:

想想堆排的整个过程,第一步建堆,第二步执行 N-1 次交换及向下调整,最后取两者复杂度较高的就行了

建堆时间复杂度:

建堆的时候时间消耗在下沉操作上,而下沉操作最多下沉到底,显然,高度为h的节点下沉代价为O(h)

堆中所有元素下沉代价之和就是建堆的时间复杂度

把堆中不同高度中的所有节点相加起来就是全部的节点

所以问题变为:

  1. 高度最高多高(高度上界)
  2. 高度h有多少节点

然后我们把不同高度的每个节点执行下沉所需要的代价累加起来

最终记住建堆复杂度为O(n)就行了

执行 N-1 次交换及向下调整时间复杂度:

Swap 操作代价为常数,相对于下沉操作的代价可以忽略不计

那么执行 N-1 次向下调整的时间复杂度为(N-1)O(\lg N)(N-1)*O(\lg N)

两个步骤相加的复杂度为:O(n)+O(nlgn),O(nlgn)复杂度高于O(n),所以堆排序的时间复杂度为O(nlgn)

提示:上面的过程有些复杂,我也是参考别人的。通过以上过程理解算法的时间复杂度是一个很棒的机会。

空间复杂度: 

堆排序通过简单的交换就能把数据排成有序的,堆和原数组是一体的,不需要辅助空间,所以空间复杂度为O(1)

稳定性: 

不是稳定的 

猜你喜欢

转载自blog.csdn.net/z_x_m_m_q/article/details/82413667