选择排序之堆排序

来源:互联网 发布:神州数码医疗科技知乎 编辑:程序博客网 时间:2024/06/05 16:05

在了解堆排序之前,必须先了解什么是堆,在了解堆的定义之前,需要了解一下什么是完全二叉树。

完全二叉树:若设二叉树深度为h,除h层外的其余层(1~h-1)的结点数达到最大,且第h层所有节点(均为叶子节点)都连续集中在左边。

堆分大顶堆小顶堆

大顶堆:具有n个元素的序列k[0],k[1]…k[n-1]当且仅当k[i]>=k[2i],k[i]>=k[2i+1],i=0,1…ceiling(n/2)-1.则称该序列为大顶堆序列;

小顶堆:具有n个元素的序列k[0],k[1]…k[n-1]当且仅当k[i]<=k[2i],k[i]<=k[2i+1],i=0,1…ceiling(n/2)-1.则称该序列为小顶堆序列;

此处的堆就是一个符合特定性质的序列。

最重要的一条性质:堆顶元素要么最大要么最小。


若以一位数组存储一个堆,则堆对应一棵完全二叉树,且该二叉树的所有非叶节点均不大于(小顶堆)或不小于(大顶堆)其子女的值。

注意:同一个非叶节点的左右两个子女值大小不作要求;只有一个子女的非叶节点至多一个。


堆排序基本思想:堆排序基本思想与简单选择排序的基本思想一致,均是从一段无序的中选出最大(或最小)的记录出来。只不过选的方式不一样而已,简单选择排序是遍历比较,而堆排序则是利用堆的性质(堆顶元素最大或最小)来选出最大(或最小)记录。具体为:先使一段无序的段调整成堆,取出堆顶元素,再使剩下的无序记录成堆,再输出堆顶记录,直至无序区剩下一个记录。

实现要点:初始序列成堆;输出堆顶元素后使剩下元素成堆;

C代码实现

void HeapAdjust(int h[],int s,int len){int temp;int child;while(s<=len/2-1)//判断s是否为一个有孩子的结点{child = 2*s+1;//左孩子下标if(child+1<len && h[child+1]<h[child])//先判断是否有右孩子,然后再右孩子是否是最小的孩子{if(h[s]>h[child+1])//判断父节点是否大于最小孩子节点{/*最小孩子节点与父节点交换值*/temp = h[s];h[s] = h[child+1];h[child+1] = temp;s = child+1;}else{return;}}else{if(h[s]>h[child])//判断父节点是否小于最小孩子节点{/*最小孩子节点与父节点交换值*/temp = h[s];h[s] = h[child];h[child] = temp;s = child;}else{return;}}}}void BuildHeap(int h[],int len){int i;for(i=len/2-1;i>=0;i--)//从最后一个有孩子的节点开始使它们的后代们成堆{HeapAdjust(h,i,len);//使i的后代们成堆}}void HeapSort(int h[],int len){int i;int temp;BuildHeap(h,len);//将无序序列成堆for(i=len-1;i>0;i--){/*将堆顶元素与无序序列的最后一个元素交换*/temp = h[0];h[0] = h[i];h[i] = temp;/*交换后无序序列的长度减1*/HeapAdjust(h,0,i);//将剩余的无序序列调整成堆}}


0 0