1.什么是堆?
堆的定义:堆是一棵完全二叉树按照顺序存储方式得到的一个数组,且满足父节点的值大于左右孩子结点的值。(大根堆)
2.维护大根堆的性质
假定:以数组A中第i个元素的左孩子、右孩子为跟结点的二叉树满足大根堆的要求,若A[i]小于其孩子的值,则违背大根堆的要求。
解决方法:
(1)找出A[i]、其左孩子、右孩子的最大值,下标为largest。
(2)如果largest == i,表明结点i满足大根堆要求,结束;
如果largest != i,表明结点i不满足大根堆要求,交换A[largest]与A[i],这样largest位置上的值是A[i],有可能以largest为根的结点违背大根堆的要求,这样的话,继续递归向下调整largest结点。
代码如下:
//维护大根堆的性质,从第i个元素向下调整
//其假定是,以当前结点i的左孩子、右孩子为根结点的二叉树是大根堆。
//len表示最后一个元素的下标。
void maxHeapify(int A[],int len, int i)
{
//找到当前节点i,左孩子、右孩子 的最大值的下标
int left = i * 2;
int right = i * 2 + 1;
int largest = i;
if (left <= len && A[left] > A[i])
largest = left;
if (right <= len && A[right] > A[largest])
largest = right;
//如果A[i]最大,则结束,否则交换A[largest]与A[i],然后递归
if (i != largest)
{
int temp = A[i];
A[i] = A[largest];
A[largest] = temp;
maxHeapify(A,len,largest);
}
}
3. 建立大根堆
用自底向上的方法利用过程maxHeapify,把数组转化为大根堆。数组的len/2之后的元素为叶结点,每个叶结点看作是只包含一个元素的堆。这样的话对其余结点依次调用maxHeapify便可。
代码如下:
//自底向上建堆,叶子结点已经是一个堆了,故从i=len/2开始调整。
void buildheap(int A[],int len)
{
for(int i = len/2; i >= 1; i--)
{
maxHeapify(A,len,i);
}
}
4.堆排序
堆排序:建好堆以后,交换第一个和最后一个元素,则最后的是最大数。如果从堆中去掉最后一个元素,使size减1,重新调整大根堆maxHeapify(A[],len, 1),再交换第一个和最后一个元素,以此类推,直到堆的size为1,结束。
代码如下:
void heapsort(int A[], int len)
{
buildheap(A,len);
for(int i = len; i>1; i--)
{
//交换换第一个和最后一个元素,size减1
int temp = A[1]; A[1] = A[i];A[i]= temp;
//调整大根堆
maxHeapify(A,i,1);
}
}
测试代码如下:
#include <iostream>
using namespace std;
int main()
{
int A[] = {0,3,2,9,7,1};
//len表示最后一个元素的下标。
heapsort(A,5);
for(int i = 1; i<6; i++)
cout<<A[i]<<" ";
return 0;
}