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


最近在学习算法导论的时候,对于堆排序这部分,在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;
	}
	else
		largest=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;
	}
}

下面是运行结果:



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值