您的位置:首页 > 其它

算法总结系列之一:堆排序(Heap Sort)

2008-06-19 14:41 513 查看
在软件设计相关领域,"堆(Heap)"的概念主要涉及到两个方面:

一种数据结构,逻辑上是一颗完全二叉树,存储上是一个数组对象(二叉堆).

垃圾收集存储区,是软件系统可以编程的内存区域.

本文所说的堆,指的是前者.另外,这篇文章中堆中元素的值,均以整型为例.

堆排序的时间复杂度是O(nlgN),与快速排序达到相同的时间复杂度.但是在实际应用中,我们往往采用快速排序而不是堆排序.这是因为快速排序的一个好的实现,往往比堆排序具有更好的表现.堆排序的主要用途,是在形成和处理优先级队列方面.另外,如果计算要求是类优先级队列(比如,只要返回最大或者最小元素,只有有限的插入要求等),堆同样是很适合的数据结构.

基础知识

堆一般用数组表示,比如数组A.数组的长度Length(A),堆在数组中的元素个数HeapSize(A).一般说来,HeapSize(A)<=Length(A),因为数组A当中可能有一些元素不在堆中.

假设节点I是数组A中下标为i的节点.

Parent(i):returnFloor(i/2);//I的父节点下标.Floor(i)表示比i小的最大整数.

Left(i):return2*i;//I的左子节点

Right(i):return2*i+1;//I的右子节点

含有n个元素的堆A的高度是:Floor(lgn)

堆的基本操作





MaxHeapify(A,i):

保持堆的性质.假设数组A和下标i,假定以Left(i)和Right(i)为根结点的左右两棵子树都已经是最大堆,节点i的值可能小于其子节点.调整节点i的位置.

算法的C#实现:

publicvoidMaxHeapify(int[]A,intheapSize,inti)

{

intleft=2*i;

intright=2*i+1;

intlarger=i;

//comparewithleftchild

if(left<=heapSize&&A[left]>A[i])

{

larger=left;

}

//comparelargernodewithrightchild

if(right<=heapSize&&A[right]>A[i])

{

larger=right;

}

//exchangeiwiththelargerchild

if(larger!=i)

{

inttmp=A[i];

A[i]=A[larger];

A[larger]=tmp;

MaxHeapfy(A,heapSize,larger);

}

}


时间复杂度与树的高度成正比,为O(lgn).

BuildMaxHeap(A):

从一个给定的数组建立最大堆.子数组A[floor(n/2)+1.......n]中的元素都是树的叶节点(完全二叉树的基本性质).从索引ceiling(n/2)开始一直到1,对每一个元素都执行MaxHeapify,最终得到一个最大堆.

算法的C#实现:

publicvoidBuildMaxHeap(int[]A)

{

intheapSize=A.Length;

for(inti=Math.Ceiling(heapSize/2);i>=1;i--)

{

MaxHeapify(A,heapSize,i);

}

}



时间复杂度依赖于MaxHeapifyO(h)(h-树的高度),BuildMaxHeap(A)的时间复杂度是O(n).




堆排序HeapSort(A):

堆排序算法的基本思想是,将数组A创建为一个最大堆,然后交换堆的根(最大元素)和最后一个叶节点x,将x从堆中去掉形成新的堆A1,然后重复以上动作,直到堆中只有一个节点.

算法的C#实现:

publicvoidHeapSort(int[]A)

{

BuildMaxHeap(A);

intHeapSize=A.Length;

for(inti=HeapSize;i>1;i--)

{

//assumethetypeofAisint[]forexample

inttmp=A[1];

A[1]=A[i];

A[i]=A[1];

HeapSize-=1; //cutoffthesortednode.

MaxHeapify(A,HeapSize,1);//sorttheA1toamaxheap

}

}


堆排序的时间复杂度是O(nlgn).



优先级队列算法-增加某元素的值(优先级):HeapIncreaseKey(A,i,key)

增加某一个元素的优先级后(元素的值),该元素应该向上移动,才能保持堆的性质.

算法的C#实现:

publicvoidHeapIncreaseKey(int[]A,intindex,intkey)

{

if(key<=A[index])

return;

A[index]=key;

while(index>1&&A[Parent(index)]<A[index]]

{

//promptchildnode

inttmp=A[index]:

A[index]=A[Parent(index)];

A[Parent(index)]=tmp;

index=Parent(index);

}

}


时间复杂度:O(lgn)


优先级队列算法-插入一个元素:Insert(S,x)将x元素插入到优先级队列S中.

主要思路是,将堆的最后一个叶节点之后,扩展一个为无穷小的新叶节点,然后增大它的值为x的值


算法的C#实现是:

publicvoidHeapInsert(int[]A,intkey)

{

A.Length+=1;

A[A.Length]=int.MinValue;

HeapIncreasekey(A,A.Length,key);

}


时间复杂度O(lgn)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
章节导航