gxc

永远不要认为有什么事情是理所当然的!

  :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

        先给出大根堆的定义:完全二叉树,任一非叶子结点都大于等于它的孩子,也就是说根结点是最大的。而且显然大根堆的任一棵子树也是大根堆。
        堆排序的基本思想是:记录区的分为无序区和有序区前后两部分;用无序区的数建大根堆,得到的根(最大的数)和无序区的最后一个数交换,也就是将该根归入有序区的最前端;如此重复下去,直至有序区扩展至整个记录区。
具体操作可按下面步骤实现:
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;
}

posted on 2005-12-24 15:46  gxc  阅读(1970)  评论(0编辑  收藏  举报