1、堆介绍:
堆排序:时间复杂度为O(nlgn)
,具有空间原址性;
堆中节点高度:该节点到叶节点最长简单路径上边的数目,n个元素的堆可以看作完全二叉树,堆的高度为lg(n)
。
最大堆:两个子树上所有节点的值均不大于它的根结点的值
2、维护堆的性质:
让A[i]
的值在最大堆中==“逐级下降”==,从而使得以下表i
为根节点的子树重新遵循最大堆性质。
伪代码:(核心代码段)
3、建立最大堆:
用自底向上的方法利用过程MAX_HEPITY
把一个大小为n的数组转化为最大堆。
伪代码:
4、堆排序算法:
首先建立最大堆,然后将根节点A[1]与A[n]交换,利用MAX_HEPIFY
调整交换后节点A[i]应该在的位置。
伪代码:
C++代码:
注意:此代码中堆顶元素为A[0]。
void HeapSort(int* A, int N) //算法入口
{
for(int i = N/2;i>=0;i--){ //自底向上,建立最大堆
max_heapify(A,i,N);
}
for(int i = N-1;i>0;i--){ // 交换堆顶元素到数组末尾,实现排序
Swap(A[0],A[i]);
max_heapify(A,0,i);
}
}
//此处用循环代替了第2部分中描述的递归
void max_heapify(int* A,int i, int j) // j代表堆中元素个数
{
int parent = i;
int tmp; //用于记录父节点的值
int child;
for(;parent*2+1<=j-1;parent = child ){ // 在左孩子节点下标没超出数组范围时循环
tmp = A[parent];
child = parent*2+1;
if(; child!=j-1 && A[child+1]>A[child]){ // 存在右孩子,且大于左孩子
child= child +1; //最大孩子为右孩子
}
if(A[parent]>A[child]) break;
else A[paernt] = A[child];
}
A[paernt] = tmp;
}
5、优先队列:
伪代码描述:
- heap_maximum(A) //返回堆最大值
return A[0];
- heap_extract_maximum(A) //删除堆最大值并返回
将末尾元素放到堆顶并调用下筛代码if(A.heap_size<1) error "heap underflow"; max = A[0]; A[0] = A[size-1]; max_heapify(A,0,size-2); return max;
- heap_insert(A,key) // 插入新值
先将插入的值放到末尾,然后其与父节点比较,大则上移。A[size] = key; int i = size; while(i>0&&A[i/2]<A[i]){ swap(A[i/2],A[i]); i = i/2; }
总结:
1、记住此部分调整最大堆的代码(下筛):“2、维护堆的性质:”
2、建立最大堆,肯定是先建立小堆再扩展,因此先从最末尾的根节点开始建立。