堆排序

来源:互联网 发布:等一分钟网络歌曲女声 编辑:程序博客网 时间:2024/05/12 00:21

思想:将数组调整为一个堆,保证父节点不小于两个子节点,这样根节点(堆顶)就是所有元素中的最大值。不断取出根节点并重新调整堆,直到堆被取完即可完成排序。

技巧:

1.关于“不断取出根节点形成有序数组”,可以将堆顶(最大值)与堆的最后一个节点交换,然后缩小堆(排除已取出的节点),然后下沉堆顶到正确的位置即可得到新的已调整的堆;

2.构造堆有两种方式,一种是从堆顶往后遍历所有节点,每次都将当前节点与父节点进行比较,使其上浮到正确的位置;另一种是从最后一个非叶子节点开始往前遍历直到根节点,每次都将当前节点与子节点进行比较,使其下沉到正确的位置。

由于技巧1中也用到下沉法,所以使用第二种方法会更加方便,同时由于只需要从最后一个非叶子节点进行遍历,效率也更高。

实现代码如下:

void heapSort(int num[], int start, int end){//从最后一个非叶子节点开始往前调用sink调整堆//调用完之后该节点之后的节点都是已调整好的小堆//当根节点调用完成之后形成一个已调整好的大堆for(int i=(start+end-1)/2;i>=start;i--)sinkForHeapSort(num, i, start, end);//大顶堆//直到堆的大小为1,则数组升序排序完成for(int j=end;j>=start;){swap(num[start], num[j]);//将堆顶的元素(最大值)与堆的最后一个节点交换j--;//缩小堆sinkForHeapSort(num, start, start, j);//重新调整堆}}

代码中可以对num[]数组的任意区域(start~end)进行排序,因此父节点和子节点的下标满足下式:

(childPos+start-1)/2=parentPos

sinkForHeapSort的实现代码如下:

//对pos位置的元素进行调整,使其下降到正确的位置void sinkForHeapSort(int num[], int pos, int start, int end){//(childPos+start-1)/2=parentPosif(pos<start||start>end) return;int childPos=pos*2-start+1;//左边子节点的坐标while(childPos<end)//如果有左边子节点和右边子节点{if(num[childPos]<num[childPos+1]) childPos++;//如果右边子节点比较大,则用右边子节点与父节点进行比较if(num[pos]>=num[childPos])break;//如果父节点比子节点都要大,则退出循环swap(num[pos], num[childPos]);//如果父节点较小,则与较大的子节点交换pos=childPos;//继续往下沉childPos=pos*2-start+1;}//只有左边子节点时,直接与左边子节点进行比较if(childPos==end && num[pos]<num[childPos]) swap(num[pos], num[childPos]);}






0 0