排序算法——堆排序

最大堆是这样一种结构:它的孩子节点的key都小于等于父节点;如果孩子节点的key都大于等于父节点,就称为最小堆。

堆排序(Heap Sort)就是利用堆进行排序的算法,它的基本思想是:

将待排序的序列构造成一个大顶堆(或小顶堆)。

此时,整个序列的最大值就是堆顶的根结点。将它移走(就是将其与堆数组的末尾元素交换,此时末尾元素就是最大值)然后将剩余的n-1个序列重新构造成一个堆,这样就会得到n个元素中的大值。

如此反复执行,便能得到一个有序序列了。

 

堆排序的过程大致分为4大步:

1.利用原来的数组建立一个最大堆。此时,数组中最大的元素肯定是在data[0]中保存的。

2.把最大堆的data[0]与data[n-1]元素交换,此时最大的元素就跑到data[n-1]中了。3.忽略最后一个元素,调整整个堆,使得元素交换以后又是一个最大堆。

4.将最大堆的data[0]与data[n-2]进行交换,以此类推。

整个程序的难点在于:如何调整一个堆,让他变为最大堆。这个问题可以递归的解决:假设某个节点的左右子树已经是最大堆了,那么如需要将根节点与左右子树相比较,然后(如果需要的话)与左右子树中最大的交换;但是交换完以后,可能会引起左右子树中的一颗不再是最大,那么就对于以左(或者右)子树为根的子树继续重复前面的过程,直到遇见叶子节点(因为对每个子树进行调整的时候,需要先和根结点比较并交换,然后再向下进行调整交换,所以递归的终结条件就是遇到叶子节点)

 

堆排序是对选择排序进行改进的排序算法,堆排序算法的时间复杂度是O(nlogn)。

//堆排序

//调整堆,使以index为根的子树成为最大堆  
void headAdjust(pArrayList list,int index,int length)
{
	//左孩子
	int lchild=index*2+1;
	//右孩子
	int rchild=index*2+2;
	int largest;//最大的下标
	
	//找出最大值的下标,存放在largest中
	if(lchild<=length&&list->data[lchild]>list->data[index])
		largest=lchild;
	else
		largest=index;
	if(rchild<=length&&list->data[rchild]>list->data[index])
		largest=rchild;
	
	//如果需要交换
	if(largest!=index)
	{
		//交换
		int tmp=list->data[index];//根结点的值
		list->data[index]=list->data[largest];
		list->data[largest]=tmp;
		//交换之后,需要判断下一级的3个结点是否需要调整
		headAdjust(list,largest,length);
	}
		
}
/*
利用数组初始化一个最大堆,就需要从最后一个叶子节点的父节点开始,
依次调用上面的heapAdjust函数就行了:
*/
//自底而上的调用headAdjust将数组变成一个最大堆
void BuildMaxHeap(pArrayList list)
{
	//从最后一个父节点开始,直到树根
	for(int i=(list->length-2)/2;i>=0;--i)
	{
		headAdjust(list,i,list->length);
	}
	
}
/*将最大堆的根与数组的最后一个元素交换,然后忽略最后一个元素,
重新调整堆。然后取倒数第二个元素重复上述步骤:
*/
//堆排序
void heapSort(pArrayList list)
{
	BuildMaxHeap(list);
	printf("构成最大堆:");
	printArrayList(list);  
    int len = list->length-1;  
	for(int i=len;i>0;i--)
	{
		int tem=list->data[0];
		list->data[0]=list->data[i];
		list->data[i]=temp;
		printf("交换以后:");
		printArrayList(list); 
		//排好以后就该忽略最后一个元素,然后考虑前n-1个元素了  
        --len;  
        headAdjust(list,0, len);  
	}
	printf("最终结果:");
	printArrayList(list);
	
}


原文链接:http://blog.csdn.net/thefutureisour/article/details/7938944

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值