java - 算法 - 大顶堆、小顶堆 排序

java - 算法 - 大顶堆、小顶堆 排序

一、完全二叉树的数组表示形式特性
最后一个父节点下标为 (len/2)-1
若当前节点的下标为i
 父节点的下标为      (i-1)/2
 左子节点的下标为    (i*2)+1 或 (i<<1)+1
 右子节点的下标为    (i*2)+2 或 (i<<1)+2
排序后特性
 大顶堆,排序后为正序;
 小顶堆,排序后为倒序;

二、运行结果

arr
	1	0	2	9	3	8	4	7	5	6	
maxHeap
	9	7	8	5	6	2	4	0	1	3	
父节点 [左子树,右子树]
	9 [7,8]
	7 [5,6]
	8 [2,4]
	5 [0,1]
	6 [3,x]
sort
	0	1	2	3	4	5	6	7	8	9	
minHeap
	0	1	2	5	3	8	4	7	9	6	
sort
	9	8	7	6	5	4	3	2	1	0	
父节点 [左子树,右子树]
	9 [8,7]
	8 [6,5]
	7 [4,3]
	6 [2,1]
	5 [0,x]
xxx

Process finished with exit code 0 

三、排序代码

package algorithm;

import utils.TeachBase;

import java.text.MessageFormat;

public class MaxHeap extends TeachBase {
    public static void main(String[] args) {
        int[] arr = new int[]{1, 0, 2, 9, 3, 8, 4, 7, 5, 6};
        print("arr", arr);
        //初始化大顶堆
        Heap max = new Heap(arr);
        max.maxHeapInit();
        print("maxHeap", max.data);
        max.printTree();
        max.maxHeapSort();
        print("sort", max.data);
        //初始化小顶堆
        Heap min = new Heap(arr);
        min.minHeapInit();
        print("minHeap", min.data);
        min.minHeapSort();
        print("sort", min.data);
        System.out.println("xxx");

    }

    public static class Heap {
        public int[] data;

        public Heap(int[] arr) {
            data = new int[arr.length];
            for (int i = 0; i < arr.length; i++) {
                data[i] = arr[i];
            }
        }

        /**
         * 初始化大顶堆
         */
        public void maxHeapInit() {
            int len = data.length;
            int lastP =  len / 2 - 1 ;
            //从最后一个父节点向上遍历
            for (int i = lastP; i >= 0; i--) {
                shiftDown(i,len);
            }
        }

        /**
         * 父节点小于左右子节点
         */
        private void shiftDown(int i,int len) {
            /**
             * 二叉树特性(若当前节点的下标为 i)
             *  最后一个父节点下标为 (len/2)-1
             *  父节点的下标为      (i-1)/2
             *  左子节点的下标为    (i*2)+1 或 (i<<1)+1
             *  右子节点的下标为    (i*2)+2 或 (i<<1)+2
             */
            //有左子节点
            int l = 0;//左子
            int r = 0;//右子
            int max = 0;
            while ((l = (i * 2 + 1)) < len) {
                //这轮循环,data[l]和data[r]交换位置
                r = l + 1;
                max = l;
                //有右子节点,且右边的更大
                if (r < len && (data[r] > data[l])) {
                    max = r;
                }
                //如果父节点大于等于左子节点,则停止循环
                if (data[i] >= data[max])
                    break;
                //左子节点比父节点值大,交换位置
                swap(data, i, max);
                //设置左子节点为父节点
                i = max;
            }
        }

        /**
         * 大顶堆排序后,正序
         */
        public void maxHeapSort(){
            for(int i= data.length -1;i>=0;i--){
                swap(data,i,0);
                shiftDown(0,i);
            }
        }

        /**
         * 初始化小顶堆
         */
        private void minHeapInit() {
            int len = data.length;
            int lastP =  len / 2 - 1 ;
            //从最后一个父节点向上遍历
            for (int i = lastP; i >= 0; i--) {
                shiftUp(i,len);
            }
        }

        /**
         * 父节点小于左右子节点
         */
        private void shiftUp(int i, int len) {
            /**
             * 二叉树特性(若当前节点的下标为 i)
             *  最后一个父节点下标为 (len/2)-1
             *  父节点的下标为      (i-1)/2
             *  左子节点的下标为    (i*2)+1 或 (i<<1)+1
             *  右子节点的下标为    (i*2)+2 或 (i<<1)+2
             */
            //有左子节点
            int l = 0;//左子
            int r = 0;//右子
            int min = 0;
            while ((l = (i * 2 + 1)) < len) {
                //这轮循环,data[l]和data[r]交换位置
                r = l + 1;
                min = l;
                //有右子节点,且右边的更小
                if (r < len && (data[r] < data[l])) {
                    min = r;
                }
                //如果父节点大于等于左子节点,则停止循环
                if (data[i] <= data[min])
                    break;
                //左子节点比父节点值大,交换位置
                swap(data, i, min);
                //设置左子节点为父节点
                i = min;
            }
        }

        /**
         * 小顶堆排序后,倒序
         */
        public void minHeapSort(){
            for(int i= data.length -1;i>=0;i--){
                swap(data,i,0);
                shiftUp(0,i);
            }
        }


        private void swap(int[] arr,int a,int b){
            int c=arr[a];
            arr[a]=arr[b];
            arr[b]=c;
        }

        /**
         * 二叉树特性(若当前节点的下标为 i)
         *  最后一个父节点下标为 (len/2)-1
         *  父节点的下标为      (i-1)/2
         *  左子节点的下标为    (i*2)+1 或 (i<<1)+1
         *  右子节点的下标为    (i*2)+2 或 (i<<1)+2
         */
        public void printTree(){
            int last = data.length/2-1;
            int l,r;
            int len = data.length;
            System.out.println("父节点 [左子树,右子树]");
            for(int i=0;i<=last;i++){
                l = (i*2) + 1;
                r = l + 1;
                System.out.println(MessageFormat.format("\t{0} [{1},{2}]"
                        ,data[i]
                        ,l<len?data[l]:"x"
                        ,r<len?data[r]:"x"));
            }
        }
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值