先给出大根堆的定义:完全二叉树,任一非叶子结点都大于等于它的孩子,也就是说根结点是最大的。而且显然大根堆的任一棵子树也是大根堆。
堆排序的基本思想是:记录区的分为无序区和有序区前后两部分;用无序区的数建大根堆,得到的根(最大的数)和无序区的最后一个数交换,也就是将该根归入有序区的最前端;如此重复下去,直至有序区扩展至整个记录区。
具体操作可按下面步骤实现:
1。建大根堆
2。交换根和无序区最后一个数
3。重建大根堆,因为交换只是使根改变了,所以左右子树依然分别是大根堆。
4。比较根,左子树的根和右子树的根,如果根最大,则无须再作调整,树已经是大根堆了;如果左子树的根最大,交换它与根,再递归调整左子树;如果右子树的根最大,交换它与根,再递归调整右子数。
5。递归调整到叶子的时候,树就是大根堆了。
现在还要解决的就是如何建那个初始的大根堆了,把整个数组R0,R1,...,R(n-1)看成一个完全二叉树,只要从后往前依次将以该结点为根的子树调整为大根堆就行了。而实际上,序号大于[n/2]的结点都是叶子结点,可看作是大根堆,所以只需调整[n/2],[n/2]-1,...,1的结点作为根节点的子树就可以了。
public static void HEAPSORT(int[] R)
{
//建初始大根堆
for (int i = R.Length / 2+Convert.ToInt32(Math.IEEERemainder(R.Length,2)); i >0 ; i--)
{
SIFT(R, i-1, R.Length-1);
}
//循环进行交换并重建大根堆
for (int j = R.Length - 1; j > 0; j--)
{
//交换根和无序区最后一个数
int t = R[0]; R[0] = R[j]; R[j] = t;
SIFT(R, 0, j-1);
}
}
public static void SIFT(int[] R,int iFrom,int iTo)
{
int i = iFrom; //根结点下标
int j = 2 * iFrom + 1; //左孩子下标
int temp = R[i]; //要调整的根结点,假定左右子树已为大根堆
while (j <= iTo)
{
if ((j < iTo) && ((R[j] < R[j + 1])))
{
j++;//如果右孩子大于左孩子,将j指向右孩子,以便接下来统一处理
}
if ((R[j] > temp))
{
//比根结点大的孩子上移
R[i] = R[j];
//指向下一个子树
i = j;
j = 2 * i + 1;
}
else
{
break;
}
}
//定位要当初的根结点到正确的位置
R[i] = temp;
}
堆排序-博客园
最新推荐文章于 2023-07-01 20:57:13 发布
0
0
(请您对文章做出评价)