您的位置:首页 > 其它

堆排序(Heap Sort)

2012-09-26 20:44 260 查看
维基百科:http://zh.wikipedia.org/wiki/堆排序

1、基本知识

二叉堆一般用数组来表示,我们可以把它视为一颗完全二叉树。数据结构中学习树这一章节时,我们知道完全二叉树可以用数组来存储。

堆的定义:

(1)大根堆:父节点的值大于等于孩子结点的值

(2)小根堆:父节点的值小于等于孩子结点的值

父节点和孩子结点下标的计算

(1)假设用数组A[1..n]来存储完全二叉树,即下标从1开始

结点i的父节点:i/2 (向下取整)
结点的左孩子结点:2*i(如果存在)
结点的右孩子结点:2*i + 1(如果存在)

(2)假设用数组A[0..n-1]来存储完全二叉树,即下标从0开始

结点i的父节点:(i-1)/2
结点i的左孩子结点: 2 * i +1(如果存在)
结点的右孩子结点:2 * i + 2(如果存在)

2、算法思想

以对数组进行升序排序为例,可以把数组建为一个大根堆,然后不断输出堆顶元素, 并调整堆,直至输出所有元素。这里采取的是数组首元素和尾元素交换,也就是把最大元置于数组尾部,每一次都可以确定一个元素的最终位置,显然堆排序算法属于原地排序。

3、代码实现

下面的代码是根据算法导论中的伪代码编写的,代码中有详细的注释。

#include <cstdlib>
#include <iostream>

using namespace std;

//父节点下标
int parent(int i)
{
return (i - 1)/2;
}

//左孩子下标
int leftChild(int i)
{
return (2 * i + 1);
}

//右孩子下标
int rightChild(int i)
{
return (2 * i + 2);
}

/*调整下标为i的结点的位置,使以其为根的子树为大根堆
假定该函数被调用时,以left(i)和right(i)为根的两棵二叉树都是大根堆
*/
template<class T>
void maxHeapify(T* a, int i, int heapSize)
{
int largest = -1;           //记录a[i]和其子女(如果存在)中最大者小标
int left = leftChild(i);
int right = rightChild(i);

if(left < heapSize && a[left] > a[i])
{
largest = left;
}
else
{
largest = i;
}

if(right < heapSize && a[right] > a[largest])
{
largest = right;
}

if(i != largest)
{
swap(a[i], a[largest]);
maxHeapify(a,largest,heapSize);
}
}

//把一个数组构建为大根堆
template<class T>
void buildMaxHeap(T* a, int heapSize)
{
int i = heapSize/2 -1;          //最后一个非叶子结点下标
for(; i>=0; i--)
{
maxHeapify(a, i, heapSize);//从最后一个非叶子结点开始自底向上调整堆
}
}

//堆排序
template<class T>
void heapSort(T* a, int n)
{
int heapSize = n;
buildMaxHeap(a, heapSize);//
// 把最大元素(堆顶元素)和堆尾元素交换,堆的大小减1,从堆顶开始自顶向下调整堆
//重复以上操作直到堆的大小为1
for(int i=n-1; i>0; i--)
{
swap(a[0],a[i]);
heapSize--;
maxHeapify(a,0,heapSize);
}
}

int main(int argc, char *argv[])
{
int n;
int *a = NULL;

while(cin>>n && n > 0)
{
a = new int
;
for(int i=0; i<n; i++)
{
cin>>a[i];
}
heapSort(a,n);
for(int i=0; i<n; i++)
{
cout<<a[i]<<" ";
}
cout<<endl<<endl;
delete [] a;
}

system("PAUSE");
return EXIT_SUCCESS;
}
4、复杂度分析

(1)对于大小为n的数组,堆的高度为lgn,

(2)调整函数maxHeapify的复杂度为O(h),即O(lgn)。

(3)heapSort中循环执行O(n)次,因而算法复杂度为O(nlgn)

算法时最坏情况下和平均情况下的时间复杂度都为O(nlogn),堆排序是渐进最优的排序算法。

参考资料:

[1]算法导论(第2版)

[2]严蔚敏《数据结构(C语言版)》
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: