用比较简单的方法实现堆排序

来源:互联网 发布:网络企鹅使用方法 编辑:程序博客网 时间:2024/06/06 13:12


最近在学习算法导论的时候,对于堆排序这部分,在CSDN上找了一篇文章,感觉代码写的比较复杂,不是很有逻辑,因此把书好好的看了一篇,按书中的思想自己完成了堆排序的代码,看起来逻辑比较清晰一些。


      分首先排序分为最大堆和最小堆,最大堆是指每个父节点的值都不小于它孩子节点的值,最小堆是指每个父节点的值都不大于它孩子节点的值,我们这里以最大堆为例进行讨论。PS:需要用到的几个小知识,编号为i的节点(树的节点都从1开始),左孩子为2i,右孩子为2i+1,父节点为i/2。


堆排序的核心步骤是如何保证每颗树满足最大堆的特性,比如现在A[LEFT],A[RIGHT]都是最大堆,但是他们2个的父节点A[I]不一定都比这2个孩子大,因此就需要调整,使这颗树成为最大堆。代码如下:


void max_heapify(int arrary[],int i,int m){if (arrary==NULL||i<=0)return ;if (i>m)return;int left,right,largest;left=2*i;right=2*i+1;if (left<=m&&arrary[left-1]>arrary[i-1]){largest=left;}elselargest=i;if (right<=m&&arrary[right-1]>arrary[largest-1]){largest=right;}if (largest!=i){int temp;temp=arrary[i-1];arrary[i-1]=arrary[largest-1];arrary[largest-1]=temp;max_heapify(arrary,largest,m);}}

传入的参数为1个数组,i为需要调整为最大堆的节点编号,m为数组元素的个数。通过比较i和他的左右子数的大小,来调整i为最大堆,此时调整了位置的largest节点可能违反了最大堆的性质,因此再调整largest这个节点为最大堆直至i下面的子树都变成最大堆。

另外一个步骤就是进行建堆,如何把数组和完全二叉树联系起来。代码如下:

void build_max_haep(int array[],int l){int m=l/2;for (int k=m;k!=0;--k){max_heapify(array,k,l);}}

一颗有l个节点的二叉树,从l/2+1开始都是叶子节点,因此从1到l/2都是有孩子的父节点,从l/2开始依次调整每颗树为最大堆,这样这步完成后,整个树就变成了最大堆。


通过上面的建堆,已经变成了最大堆,那么A[0]就是数组中最大的节点啦,现在要排序应该怎么办呢?

void heap_sort(int array[],int length){build_max_haep(array,length);for (int i=length;i!=1;--i){int temp;temp=array[0];array[0]=array[i-1];array[i-1]=temp;--length;max_heapify(array,1,length);}}

这个for循环,就是把A[0]和数组中最后1个元素交换,那么最大的值就到A[i-1]中去了,此时在把1到i-1的元素继续调整为最大堆,得到最大的值放到A[i-2]中,这样最后A[]数组就变成从小到的的数组了。

void main(){int a[]={8,2,4,7,1,14,9,10,3,16};heap_sort(a,sizeof(a)/sizeof(a[0]));for (size_t ix=0;ix!=sizeof(a)/sizeof(a[0]);++ix){cout << a[ix] <<endl;}}

下面是运行结果:



原创粉丝点击