您的位置:首页 > 其它

堆排序

2015-11-17 08:55 162 查看
转载自:/article/2357990.html

堆

堆是一个完全二叉树的数组对象。树每一层都是满的,最后一层可能除外(从一个节点的左子树开始填)。






给定节点i,可以很容易计算父节点和子节点的位置。


Parent(i)=floor(i/2):i/2再向下取整


LeftChild(i)=2*(i+1)-1:因为i从0开始,这和c语言的数组从0开始相对应。可以用左移运算代替*,即LeftChild(i)=(i+1)<<1-1;


RightChild(i)=2*(i+1):RightChild(i)=(i+1)<<1;






堆排序


堆排序的时间复杂度是O(nlgn),是比较有效率的一种。其使用的是最大堆。最大堆的意思是父节点的值>=孩子的值。那么第0个节点必定是该堆的最大值。所以,堆排序的思想就是每次循环把最大值移走,然后从剩下的节点重新建立最大堆。


第一步:建立堆的结构体。



[cpp]viewplaincopy

typedefstructheap_t{

int*arr;//pointforanarraytostoreheapvalue.

intheapMaxIndex;//heapelementmaxindexnumber

intarrLength;//arraylengthofarr

}Heap;


其中arr指针指向的是存放堆数据的数组。


heapMaxIndex是数组最大的序号。如数组定义为a[10],那么heapMaxIndex的值应该为9.




第二步:保持堆的性质。


这一步是堆排序的基础。这里将功能写成一个函数名为voidmaxHeapify(Heap*hp,unsignedintnodei),这个函数用于让一个数组变成一个符合堆性质的数组。时间复杂度为O(h),h是堆所属二叉树树的高度=lgn(n是节点个数)。


思想是:从一个节点i,和他的孩子leftchild(i),rightChild(i)中找到最大的,然后其索引存放在largest中。如果i是最大的。那么i为根的子树已经是最大堆,程序结束。


否则i的某个子节点有最大元素,那么i的值和largest的值交换。下标为largest的节点在交换后作为父节点,那么他可能又违反堆性质,因此递归调用该函数。





[cpp]viewplaincopy

voidmaxHeapify(Heap*hp,unsignedintnodei)

{

unsignedintl=(nodei+1)<<1-1;//leftchild=2i-1,-1?:arr[0..n-1]

unsignedintr=(nodei+1)<<1;//rightchild=2i

unsignedintlargest=0;

intheapMaxI=hp->heapMaxIndex;

if(l<=heapMaxI&&hp->arr[l]>hp->arr[nodei])

largest=l;

else

largest=nodei;

if(r<=heapMaxI&&hp->arr[r]>hp->arr[largest])

largest=r;

if(largest!=nodei)

{

//exchange

inttmp;

tmp=hp->arr[largest];

hp->arr[largest]=hp->arr[nodei];

hp->arr[nodei]=tmp;

maxHeapify(hp,largest);

}else{

return;

}

}




                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: