排序算法总结(三)

堆排序

1.堆

  堆实际上是一棵完全二叉树,其任何一非叶节点满足性质:

 Key[i]<=key[2i+1]&&Key[i]<=key[2i+2]或者Key[i]>=Key[2i+1]&&key>=key[2i+2],满足Key[i]>=Key[2i+1]&&key>=key[2i+2]称为大顶堆,满足 Key[i]<=key[2i+1]&&Key[i]<=key[2i+2]称为小顶堆。大顶堆的堆顶的关键字肯定是所有关键字中最大的,小顶堆的堆顶的关键字是所有关键字中最小的。

2.堆排序的思想

    利用大顶堆(小顶堆)堆顶记录的是最大关键字(最小关键字)这一特性,使得每次从无序中选择最大记录(最小记录)变得简单,堆排序的时间复杂度和归并排序,快速排序一样都是O(nlogn)。

    其基本思想为(小顶堆):

    1)将初始待排序关键字序列(R0,R2....Rn-1)构建成小顶堆,此堆为初始的为数组,他是无序的;

    2)将堆顶元素R[0]与最后一个元素R[n-1]交换,此时得到新的无序区(R0,R2,......Rn-2)和新的有序区(Rn),且满足R[1,2...n-1]>=R[n]; 

    3)由于交换后新的堆顶R[0]可能违反堆的性质,因此需要对当前无序区(R1,R2,......Rn-1)调整为新堆,然后再次将R[0]与无序区最后一个元素交换,得到新的无序区(R1,R2....Rn-2)和新的有序区(Rn-1,Rn)。不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成。

操作过程如下:

     1)初始化堆:将R[0..n-1]构造为堆;

     2)将当前无序区的堆顶元素R[0]同该区间的最后一个记录交换,同时将堆的长度做size--,然后将新的无序区调整为新的堆。

     3)不断的重复2的操作直到size=0停止;

列子如下: 给定一个整形数组a[]={16,7,3,20,17,8},对其进行堆排序。

如下面图,画的不好看;


    简而言之就是:数组写成二叉树形式----调整为小顶堆----首尾互换------调整为小顶堆------首尾互换------直到size=0;

代码如下:

    

//整理节点time:O(lgn)
template<class T>
void MinHeapify(T arry[], int size, int element)
{
	int lchild = element * 2 + 1, rchild = lchild + 1;//左右孩子
	while (rchild<size)      //子孩子均在范围内
	{
		if (arry[element] <= arry[lchild] && arry[element] <= arry[rchild])//如果比左右孩子都小,完成整理
		{
			return;
		}
		//不论是左右边哪边最小,都将最小的那个交换为子父节点

		if (arry[lchild] <= arry[rchild]) //如果左边最小
		{
			swap(arry[element], arry[lchild]);//把左面的提到上面
			element = lchild;                 //循环时整理子树
		}
		else                                  //否则右面最小
		{
			swap(arry[element], arry[rchild]);//同理
			element = rchild;
		}
		lchild = element * 2 + 1;
		rchild = lchild + 1;//重新计算子孩子位置
	}
	if (lchild<size&&arry[lchild]<arry[element])    //子父左孩子判断
	{
		swap(arry[lchild], arry[element]);
	}
	return;
}
//堆排序time:O(nlgn)
template<class T>
void HeapSort(T arry[], int size)
{
	int i;
	//从子树开始整理树,最后变为小顶堆
	for (i = size - 1; i >= 0; i--)
	{
		MinHeapify(arry, size, i);
	}
	while (size>0)
	{
		swap(arry[size - 1], arry[0]);//将根(最小)与数组最末交换
		size--;                       //树长度减小
		MinHeapify(arry, size, 0);    //整理树重新变为小顶堆
	}
	return;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值