Java的堆排序--算法笔记

堆排序

堆排序使用二叉树的一些思想以及结论,但并没有真正的建立树。一切的操作都是在操作数组
有些专用的词可能使用不对,但算法思想和代码实现绝对没有问题

  1. 关于完全二叉树

    一个一维数组对应一个完全二叉树,在不越界并且子节点,父节点都存在时,一个结点(索引为 index)的父节点在数组中对应的索引为(index-1)/2,左子节点2index+1,右子节点2index+2。数组从0开始存储。

  2. 大顶堆与小顶堆
    在一个二叉树中,所有的父节点都大于两个子节点,这就是大顶堆
    在一个二叉树中,所有的父节点都小于两个子节点,这就是小顶堆
    但是左右子节点不分大小,所以,树的根节点一定是最大或最小的。

  3. 将一个半有序的树变成大顶堆,部分有序化
    在这里插入图片描述
    如图的树,可以发现,根节点的左子树和右子树都有序,只是根节点不对,我们先将这种树,变成大顶堆。
    1、比较左右两个结点,将最大的和父节点交换,此时,变成下图
    在这里插入图片描述
    2、可以发现,这次是和左边交换,并且,左子树的有序结构被改变,右边并没有改变,所以,我们应该继续在把以7为根结点的树,继续有序化。而右边的情况不会改变。
    向左递归就可以完成。如下图。
    在这里插入图片描述
    3、代码实现

    //部分有序化函数
    //参数,head,该节点,树中的节点数
    void heap(int head,int n){
            if(head>=n){
                return;
            }
            int max=head;
            int c1=head*2+1;
            int c2=head*2+2;
            记录最大值的下标
            if(c1<n&&arr[c1]>arr[max]){
                max=c1;
            }
            if(c2<n&&arr[c2]>arr[max]){
                max=c2;
            }
            if(max!=head){
                exchange(head,max);//交换这两个节点的值的函数
                //和哪边交换,才有可能改变那边的结构,所以在对其有序化,使用递归
                heap(max,n);
            }
        }
    
    	//交换这两个节点的值的函数
        void exchange(int a,int b){
        int tmp;
        tmp=arr[a];
        arr[a]=arr[b];
        arr[b]=tmp;
    }
    
  4. 将一个任意的树,转成大顶堆;
    任意一个树,变成大顶堆,只要从最后一个非叶子节点,依次向上,做部分有序化,直到根节点就可以,
    1、如何找到从最后一个非叶子节点:其实他就是最后一个节点的父节点,使用上面的结论,最后一个非叶子节点=(n-1)/2;其他的依次递减,直到根节点,这样,就可以把任意一个树,转换成大顶堆。
    2、代码实现

    ```
    //参数,n,当前树的结点个数
    void build_heap(int n){
            int tmp=(n-1)/2;//找到从最后一个非叶子节点
            //依次递减到根节点
            for(int i=tmp;i>=0;i--){
                heap(i,n);//调用部分有序化的方法
            }
        }
    ```
    
  5. 使用大顶堆排序
    1、我们建成这样一个树,为什么?其实是想找到最大会最小的数,他一定位于根节点。
    2、我们只要将他和最后一个交换,这时再将交之换后的树,去掉最后一个结点,在找到第二大的数,在放到最后,在去掉最后一个结点,直到结束。
    3、这时,这个树的最大结点在最后,最小结点在最上面,这个完全二叉树有对应一个一维数组,这个一维数组,就是由小到大排列。

    void treeSort(){
            build_heap(arr.length);//得到最大堆
            //循环,i记录最后一个节点的下标,依次递减,就是依次将最后一个从树中去掉
            for(int i=arr.length-1;i>=0;i--){
                exchange(0,i);//交换根节点和最后一个结点
                build_heap(i);//重新得到去掉最后一个结点后的最大堆
            }
    
        }
    

完整的代码

//用来排序的类
class TreeArrSort{
     int arr[];
    //构造器,传入要排序的数组
    TreeArrSort(int[] arr){
        this.arr=arr;
    }

    void heap(int head,int n){
        if(head>=n){
            return;
        }
        int max=head;
        int c1=head*2+1;
        int c2=head*2+2;
        if(c1<n&&arr[c1]>arr[max]){
            max=c1;
        }
        if(c2<n&&arr[c2]>arr[max]){
            max=c2;
        }
        if(max!=head){
            exchange(head,max);
            heap(max,n);
        }
    }

    void exchange(int a,int b){
        int tmp;
        tmp=arr[a];
        arr[a]=arr[b];
        arr[b]=tmp;
    }

    void build_heap(int n){
        int tmp=(n-1)/2;
        for(int i=tmp;i>=0;i--){
            heap(i,n);
        }
    }

    void treeSort(){
        build_heap(arr.length);
        for(int i=arr.length-1;i>=0;i--){
            exchange(0,i);
            build_heap(i);
        }

    }
}

使用示意

public class TreeSort {
    public static void main(String[] args) {
        int arr[]=new int[]{5,8,7,4,3,7,54,7,23,6,7,2};//待排序数组
        TreeArrSort tas=new TreeArrSort(arr);//排序类
        tas.treeSort();//调用排序函数
        //打印结果
        for(int k:arr){
            System.out.print(k+" ");
        }
    }
}

输出情况

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值