排序算法(七):堆排序

9 篇文章 0 订阅

一、算法原理
堆排序(Heap sort)使用堆这样一种数据结构来进行数据管理,它与归并排序相同但不同于插入排序的是时间复杂度是O(nlogn);它与插入排序相同,但不同于归并排序的是具有空间原址性(任何时候都只需要常数个额外的元素空间存储临时数据)。因此堆排序结合了这两种排序算法的优点。
堆(二叉堆)是一个数组,可以被看成一棵完全二叉树,除了最底层外,该树是完全充满的,而且是从左向右填充。给定一个节点下标i(下标从1开始,不适用0),可以很容易计算出它的父节点、左孩子和右孩子的下标:

节点下标
父节点i / 2
左孩子2 * i
右孩子2 * i + 1

在堆排序算法中,使用最大堆(堆的每个节点都比它的孩子节点大),排序时将堆顶元素与最后一个元素交换,然后堆的规模减一,恢复堆的性质。
二、算法描述
主要三个方法的调用

  • MaxHeapify方法:维护最大堆的性质,通过让A[i]的值在最大堆中”逐级下降“,从而使得以i为根节点的子树遵循最大堆的性质。具体过程是:假设节点A[i]的左右子树都是最大堆,在每一次函数调用中,从A[i]、A[Left(i)]和A[Right(i)]之间确定最大的一个,将其下标保存在largest中,如果A[i]是最大的,那么以i为根节点的子树已经是最大堆;如果最大元素是某个孩子节点,则交换A[i]与A[largest]的值,从而使i及其孩子节点保持最大堆的性质。交换之后,下标为largest的节点作为根节点的子树又可能会违反最大堆性质,因此递归调用maxHeapify方法。
  • BuildMaxHeap方法:自底向上利用maxHeapify方法把一个规模为n = A.length的数组A[1…n]转换为最大堆。叶节点是A[n/2+1…n],每个叶节点都可以看作是只包含一个元素的堆。buildMaxHeap方法就是对其他每个节点都调用一次maxHeapify方法。
  • HeapSort方法:首先利用BuildMaxHeap方法把输入数组建成最大堆,因为数组中的最大元素总在根节点A[1],通过把它和数组末尾元素A[n]交换,可以让该元素处于正确的位置。然后从堆中去掉节点n,在剩余的节点中,新的根节点可能会违背最大堆的性质。为了维护最大堆的性质,再调用MaxHeapify方法,将根节点下沉,在A[1…n-1]中再构建一个新的最大堆。堆排序算法不断重复这个过程,直到堆的大小从n降到2。

如果要求数组按降序排列,则可以维护一个最小堆,用于堆排序,方法与上述堆排序算法相反。

三、算法复杂度
堆排序算法的时间复杂度最坏情况是T(n) = O(nlogn),最优情况是T(n) = O(nlogn),平均情况是T(n) = O(nlogn)。

四、示例代码

//交换数组中的两个元素
void exchange(int * a, int * b)
{
	int temp = *a;
	*a = *b;
	*b = temp;
}

//维护最大堆的性质
void MaxHeapify(int A[], int size, int index)
{
	int left = 2 * index;         //左孩子下标
	int right = 2 * index + 1;    //右孩子下标
	int largest = index;          //保存三个节点最大值的下标
	
	//确定节点index与其左右孩子之间值最大的节点的下标
	if(left <= size && A[left] > A[largest])
		largest = left;
	if(right <= size && A[right] > A[largest])
		largest = right;
	
	//若最大节点在孩子节点,交换这两个节点,然后递归地往下继续
	if(largest != index)
	{
		exchange(&A[index], &A[largest]);
		MaxHeapify(A, size, largest);    
	}
}

//创建最大堆,堆的数据从A[1]开始
void BuildMaxHeap(int A[], int length)
{
	int size = length;
	//初始化时,从A[size/2]位置开始
	for (int i = size / 2; i >= 1; i--)
	{
		MaxHeapify(A, size, i);
	}
}

//堆排序
void HeapSort(int A[], int length)
{
	BuildMaxHeap(A, length);
	
	int size = length;
	while (size > 1)
	{
		exchange(&A[1], &A[size]);  //将数组顶端最大的元素交换至数组末尾
		size--;                     //堆规模减一
		MaxHeapify(A, size, 1);     //维护最大堆的性质
	}		
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值