堆排序之构建大顶堆

 1、完全二叉树:是一种特殊的二叉树,要求数据从上到下、从左到右,依次进行平铺。即先放上边再放下面,先放左边再放右边你,左边没有放完,右边就不可以放数据。正如图1中一组数据的0不可以放在4的下面,应该优先放在7的下面。而7必须作为5的左子树而不能成为右子树。

图1

2、大顶堆小顶堆:大顶堆是在完全二叉树的基础上,每个节点的值都大于或等于其左右孩子的值。小顶堆是在完全二叉树的基础上,每个节点的值都小于或等于其左右孩子的值。还是上面那组数据,将其改为大顶堆如图2

父节点一定大于其左右孩子的值,我们这里只说直接亲子关系,不说兄弟节点的孩子节点。所以只要7大于孩子节点上的所有的值,6大于其孩子的值,4大于孩子的值就可以,5跟4之间没有关系。

堆排序第一步:由完全二叉树构建出大顶堆(如上步骤)

堆排序第二步:堆元底元素和堆顶元素进行互换(如图3),交换完成之后堆底元素不再参与构建

图3

 第三步:重新构建大顶堆(图4),构建完成后堆底元素和堆顶元素进行互换(图5)

图4
图5

实际构建过程不可能在完全二叉树上构建 (代码量太大),所以我们只需要去利用完全二叉树的特点去构建大顶堆。

当给每个数据一个下标,会发现,任何一个节点的左子节点arr[i]=arr[2i+1],任何一个节点的右子节点arr[i]=arr[2i+2],任何一个节点的父节点arr[i]=arr[(i-1)/2]。且数据有子树先有左子树,因为数据是从左到右排序的(图6)

图6

由完全二叉树构建大顶堆过程:定义一个指针叫parent,再定义一个指针叫child。(图7)

1、parent游标从后向前移动(即61302),如果当前节点没有子树直接跳过 

2、如果当前节点有子树,先让child游标指向其左子树(因为有树一定先有左子树)

3、判断该节点有没有右子树,如果有则child游标指向左右子树当中最大的值

4、parent所指的是当前节点,当前节点和child节点的值进行对比,如果当前节点的值大于child节点的值,parent游标继续向前移动

5、如果当前节点值小于child节点的值,父子节点的值进行交换

   5.1 parent游标指向child游标的位置,child游标的地址 = 2*child+1

      5.1.1 如果child游标指向空,parent游标继续向前移动

      5.1.2 如果child游标指向不为空则重复第5步

图7

构建大顶堆代码如下 

public static void main(String[] args){
    int[] aee = new int[]{};
    for(int p = 1;p<arr.length-1;p>=0;p--){
       sort(arr,p); 
    }
}

public static void sort(int[] arr,int parent){
    //定义左子树
    int child = 2 * parent + 1;
    while(child < arr.length){
    //排序
    //判断有没有右子树,以及比较右子树谁大,child指针指向大的
    int rchild = child + 1;
        if(rchild <+ arr.length - 1 && arr[rchild] > arr[child]){
            child++;
        }
        //父子节点进行对比交换
        if(arr[parent] < arr[child]){
            //交换
            int temp = arr[parent];
            arr[parent] = arr[child];
            arr[child] = temp;
            parent = child;
            child 2 *child + 1;
        }
    }
    else{
        break;
    }

}

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值