堆排序

堆排序

堆排序是将序列人为的类比做堆来处理,分为大堆和小堆,大堆就是双亲结点大于孩子结点,这里的孩子自身可能也是“双亲”,那么这个“双亲”还要大于它的孩子,小堆于此相反。 
当所有结点满足这个大堆的条件后,最上面的根节点肯定是这个序列中最大的数,然后我们将这个数与最后一个结点交换,再对除了最后一个结点外的所有结点进行大堆处理,依次反复,最终会将这个序列排成从小到大的顺序。

下面,让我们结合图来详细的说明: 
以序列a[] = {29, 17, 35, 6, 12, 31, 28, 15}为例; 
整个遍历的过程是从最后一个非叶子节点开始,依次将所有非叶子结点遍历完成;

首先将序列按照顺序排成二叉树的模样: 
这里写图片描述

这里我们需要知道几个知识点: 
1.最后一个非叶子结点的下标为:length / 2 - 1 ; 
2.假设根节点的下标为i,其左孩子的下标为2 * i + 1,右孩子的下标为2 * i + 2;

第一次遍历: 
6是最后一个非叶子节点,比较其与孩子结点的大小,发现6<15,于是交换两者的内容,并将15作为双亲,继续与它的孩子进行比较,但15并没有孩子,于是第一次遍历结束,结果如下图; 
这里写图片描述

第二次遍历: 
35是倒数第二个非叶子结点,比较其与孩子结点的大小,35大于它所有的孩子结点,所以不进行交换,本次遍历结束; 
这里写图片描述

第三次遍历: 
17是倒数第三个非叶子结点,比较其与孩子结点的大小,17大于它所有的孩子结点,所以不进行交换,本次遍历结束; 
这里写图片描述

第四次遍历: 
29是倒数第四个非叶子结点,比较其与孩子结点的大小,发现29<35,于是交换二者内容(此时35在下标为0的位置,29在下标为2的位置) 
这里写图片描述

之后,再将29作为双亲与它的孩子结点比较大小,发现29 < 31,于是交换二者内容(此时31在下标为2的位置,29在下标为5的位置) 
这里写图片描述

最后,将29与其孩子结点进行比较,并没有孩子结点,本次遍历结束。 
通过这四次遍历,这个二叉树已经满足大堆的要求,并且最大数35在最上面,对应于下标0的位置。于是将35与最后一个结点交换内容,(此时35的下标为7)并对除去35以外的所有结点再次执行大堆操作。 
这里写图片描述


新一轮遍历

第一次遍历: 
31作为最后一非叶子结点,与其孩子进行比较,并没有比它大的孩子,于是本次遍历结束; 
这里写图片描述

第二次遍历: 
17是倒数第二个非叶子结点,比较其与孩子结点,并没有比它大的孩子结点,于是本次遍历结束; 
这里写图片描述

第三次遍历: 
将6与其孩子结点比较大小,并且最大的孩子结点是31,所以将31与6进行交换(此时,31在下标为0的位置,6在下标为2的位置) 
这里写图片描述 
将6再与孩子结点进行比较,将最大孩子结点与其交换内容(此时,29在下标为2的位置,6在下标为5的位置) 
这里写图片描述

再次将6与其孩子结点进行比较,并不存在孩子结点,所以本次遍历结束; 
通过这三次遍历,这个二叉树已经满足大堆的要求,并且最大数31在最上面,对应于下标0的位置。于是将31与最后一个结点交换内容,(此时31的下标为6)并对除去31以外的所有结点再次执行大堆操作。 
这里写图片描述


新一轮遍历:

第一次遍历: 
29是最后一个非叶子结点,比较其与孩子结点的大小,并没有比它大的孩子结点,此次遍历结束; 
这里写图片描述

第二次遍历: 
17是倒数第二个非叶子结点,比较其与孩子结点的大小,并没有比它大的孩子结点,此次遍历结束; 
这里写图片描述

第三次遍历: 
28与其叶子结点比较大小,发现29>28,于是交换二者内容(此时29在下标为0的位置,28在下标为2的位置) 
这里写图片描述

将28与其孩子结点比较大小,并没有大于它的孩子结点,于是本次遍历结束; 
通过这三次遍历,将最大数29移到下标为0的位置,于是将 29与最后一个结点交换内容,即6在下标为0的位置,29在下标为5的位置,再对除去29以外的所有数进行大堆操作; 
这里写图片描述

之后的过程以前面相同。

以下是代码:

void heapadjust(Arr arr,int n,int m)//对堆进行调整
{
	Elementype temp = arr[n];//用temp来保存双亲节点的数值
	int i;
	for(i = 2*n+1;i <= m;i = 2*i+1)
	{
		if(i < m && arr[i] < arr[i+1])//比较左右子叶的大小
			i++;
		if(arr[i] < temp)//左右子叶中较大的与双亲节点比较
			break;
		arr[n] = arr[i];//如果子叶的数值大于双亲节点,将这个数值赋值给双亲节点
		n = i;
	}	
	arr[n] = temp;//将原来双亲节点的数值赋值给子叶
}

void heap(Arr arr)//堆排序
{
	int i;
	for(i = (MAX-2)/2;i >= 0;i--)//初始化堆
		heapadjust(arr,i,MAX-1);//进行堆调整
	for(i = MAX - 1;i > 0;i--)
	{
		swap(arr,0,i);//将首节点(数值最大)调到最后一位
		heapadjust(arr,0,i-1);//将剩下的数在进行堆排,将最大数依次排列
		print(arr);
	}	
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值