排序算法总结之堆排序 Heap Sort

算法原理:


堆排序算法利用二叉堆进行排序。最大堆得到升序的数组,最小堆得到降序的数组。

1. 构建最大堆(最小堆)
2. 从堆中取出根节点
3. 维护最大堆(最小堆)


堆:

堆的是二叉树的一种,实际上是数组对象。树上的节点和数组中的元素相对应,每一层从左到右填满,只有最后一层可能不满。



数组下标从1开始时,父节点下标和左右节点下标的关系为:PARENT(i) = i/2      LEFT(i) = 2 * i        RIGHT(i) = 2 * i + 1

最大堆:A[PARENT(i)] >= A[i]                  最小堆: A[PARENT(i)] <= A[i]


堆的基本操作:

操作 描述 时间复杂度
build 建立一个空堆 O(n)
insert 向堆中插入一个新元素 O(\log n)
update 将新元素提升使其符合堆的性质  
get 获取当前堆顶元素的值 O(1)
delete 删除堆顶元素 O(\log n)
heapify 使删除堆顶元素的堆再次成为堆


算法伪代码:


算法伪代码出自算法导论堆排序部分:

1. 建堆,当堆的大小为n时,堆的叶子节点的下标为n/2+1, n/2+2,...n
BUILD-MAX-HEAP(A)
heap-size[A] = length[A]
for i=length(A)/2 to 1
do MAX-HEAPFY(A, i)

 2. 维护堆

MAX-HEAPFY(A, i)

l = LEFT(i)

r = RIGHT(i)

if l<= heap-size[A] and A[l] > A[i]

then largest = l

else largest = i

if r<= heap-size[A] and A[r] > A[largest]

then largest = r

if largest != i

then exchange A[i] - A[largest]

MAX-HEAPFY(A, largest)

3. 堆排序

HEAPSORT(A)

BUILD-MAX-HEAP(A)

for i=length[A] to 2

do exchange A[1] - A[i]

heap-size[A] = heap-size[A] - 1

MAX-HEAPFY(A, 1)


算法性能分析:


时间复杂度:分析堆排序算法的时间复杂度需要先分析建堆和维护堆的时间复杂度,而分析建堆的时间复杂度需要先分析维护堆的时间复杂度,因此从维护堆的时间复杂度开始分析。

维护堆(MAX-HEAPFY)时间复杂度:MAX-HEAPFY函数调整第i个元素使以i为根的堆成为最大堆,调整A[i], A[LEFT(i)]和A[RIGHT[I]]的代价为O(1), 然后递归的向下调整发生改变的子树使之保持最大堆。算法导论这部分书中为我们证明了每个子书大小最多为2n/3。因此,递归的时间复杂度计算公式可以写成:

T(n) <= T(2n/3) + O(1)

得到T(n) = O(logn)


建堆(BUILD-MAX-HEAP)的时间复杂度:从最后一个非叶子节点开始使用MAX-HEAPFY向上调整整棵树,每个子树都成为一个最大堆。每次MAX-HEAPFY的时间已经推出为O(logn), 调用的次数为O(n),因此所需的时间为O(nlogn)


堆排序算法时间复杂度:首先调用BUILD-MAX-HEAP把数组调整为最大堆,需要的时间复杂度为O(nlogn)。把堆顶元素和堆的最后一个元素交换,需要的时间为O(1), 然后调整剩下的元素维护最大堆,调用n-1次MAX-HEAPFY,需要的时间复杂度为O(nlogn)。因此,堆排序的时间复杂度为O(nlogn)。


空间复杂度:O(1)

稳定性:不稳定


Java版本实现代码:

private void build(int[] A)
	{
		for(int i=A.length/2-1;i>=0;i--)
		{
			heapfy(A, i, A.length);
		}
	}
	
	private void heapfy(int[] A, int i, int len)
	{
		int left = 2*i+1;
		int right = 2*i+2;
		int largest;
		if(left < len && A[left]>A[i])
			largest = left;
		else
			largest = i;
		if(right < len && A[right] > A[largest])
			largest = right;
		if(largest != i)
		{
			int temp = A[i];
			A[i] = A[largest];
			A[largest] = temp;
			heapfy(A, largest, len);
		}
	}
	
	private void sort(int[] A)
	{
		build(A);
		int size = A.length;
		while(size > 0)
		{
			int temp = A[0];
			A[0] = A[size-1];
			A[size-1] = temp;
			size--;
			heapfy(A, 0, size);
		}
	}


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值