堆排序算法依靠堆的性质来达到排序的目的,此处的堆不同于程序中的堆,此处的堆的逻辑形态是一棵完全二叉树,树根的值大于左右孩子的值,子树也满足这个性质,这样的堆称为大顶堆,反之成为小顶堆。因此堆顶的元素就是最大或最小的元素。因此,给定一个有n个元素的序列,就可根据堆的形态和性质把序列调整为一个堆,然后交换堆的堆顶元素和堆的最后元素,再对长度为n-1的序列进行堆调整,直到序列长度为1,此时序列已排好序。时间复杂度是O(nlgn),空间复杂度O(1)。
利用堆,还可以实现优先队列,依据优先级的高低来建堆,堆顶元素就是最大优先级或最小优先级。我的csdn资源里有我的一个实现。
另外,对于找出海量数据的前N大元素或前N小元素,堆提供了一个可行的解决方案。如果是找出前N大元素,可以先读取N个元素建成一个最小堆,然后一次读取一个元素,与堆顶元素比较,如果大于堆顶元素,则替换掉堆顶元素,再调整成新的堆,直至所有元素读取完毕,最后堆里的元素就是要求的答案。如果是找出前N小元素,则建大顶堆,其余操作一样。这种方法对机器的内存要求很低,因此可用来处理海量数据。我的csdn资源里有这种方法的实现。
下面给出堆排序的实现代码:
//MaxHeap.hpp
#ifndef MAXHEAP_H
#define MAXHEAP_H
/************最大堆************/
//堆调整
template<class type>
void maxHeapify(type *A, int i, int n)
{
type key = A[i];
for (int k=2*i+1; k<n; k=2*i+1)//k为左孩子
{
if (k+1<n&&A[k]<A[k+1])//k+1是右孩子,一定要加k+1<n,找出左右孩子中的最大值
k++;
if (key<A[k])
{
A[i] = A[k];
i = k;
}
else //根最大,不用再调整
break;
}
A[i] = key;
}
//建堆
template<class type>
void buildMaxHeap(type *A, int n)
{
if (!A)
return;
for (int i=n/2 - 1; i>=0; i--)//从第一个有孩子的元素开始调整,下标是n/2-1
maxHeapify<type>(A, i, n);
}
#endif
//HeapSort.hpp
#ifndef HEAPSORT_H
#define HEAPSORT_H
#include <algorithm>
using namespace std;
#include "MaxHeap.hpp"
//堆排序
void heapSort(int *A, int n)
{
if (!A)
return;
buildMaxHeap<int>(A, n);
for(int i=n-1; i>0; i--)
{
swap(A[i], A[0]);
maxHeapify<int>(A, 0, i);
}
}
#endif