Java手写堆

小根堆介绍

这里以小根堆为例
最大堆和最小堆是二叉堆的两种形式。
小根堆:根结点的键值是所有堆结点键值中最小者,且每个结点的值都比其孩子的值小。
大根堆:根结点的键值是所有堆结点键值中最大者,且每个结点的值都比其孩子的值大。

堆的父元素与子元素对应数组的索引有如下关系

设根节点索引从1开始

  • 当父节点索引为n时,左孩子节点2n , 右孩子索引2n+1。
  • 当前节点为 n, 那么它的父节点为n/2。

代码实现

自定义小根堆类

public class MyHead {
    private int[] headArr; // 存放数据的数组 (0下标不存值)
    private int headSize=0; // 堆的大小
    private int maxSize; // 数组最大值

    // 构造函数
    public MyHead(int maxSize) {
        this.maxSize = maxSize;
        this.headArr = new int[maxSize];
    }
}

数组元素交换位置方法(便于交换)

// 两个数组元素进行交换
void swap(int[] arr, int index1, int index2) {
    int temp = arr[index1];
    arr[index1] = arr[index2];
    arr[index2] = temp;
}

添加元素

// 添加元素
    void put(int num) {
        if (headSize == maxSize-1) {
            System.out.println("堆已满!");
            return;
        }
        /**
         * 1、堆的大小+1                 ++headSize
         * 2、将插入的数放入堆尾          headArr[headSize] = num
         */
        headArr[++headSize] = num;
        // 操作数刚开始的下标是堆尾元素下标 curIndex = headSize
        int curIndex = headSize;
        // 重新调整为小根堆 (shiftUp)
        shiftUp(curIndex);
    }
    // 插入堆时 上移(若当前状态不满足小根堆)
    private void shiftUp(int curIndex) {
        while (curIndex > 1) {  // 判断不是根节点
            // 父节点为 当前节点/2   curIndex>>1 等同于 curIndex/2
            int fatherIndex = curIndex>>1;
            if (headArr[fatherIndex] > headArr[curIndex]) { // 如果当前节点比父节点还小 交换
                swap(headArr, curIndex, fatherIndex);
                // 交换之后 当前节点的下标也换了
                curIndex = fatherIndex;
            }else break;
        }
    }	

获取根节点元素,并删除

 // 获取最小值元素 并移除
    int pop() {
        if (headSize == 0) {
            System.out.println("堆已空!");
            return -1;
        }
        // 获取最小值元素(根节点既为最小值)
        int minNum = headArr[1];
        /**
         * 1、将堆尾部元素覆盖给arr[1]位置  headArr[1] = headArr[headSize]
         * 2、将堆的大小减1                headSize--
         */
        headArr[1] = headArr[headSize--];
        // 因为队尾元素值已经覆盖到根节点位置 接下来的操作数便是这个值
        int curIndex = 1;
        // 重新调整为小根堆 (shiftDown)
        shiftDown(1);
        return minNum;
    }
    // 堆删除根节点元素时 下移(若当前状态不满足小根堆)
    private void shiftDown(int curIndex) {
        while (curIndex*2 <= headSize) { // 存在左孩子(存在子节点)
            int leftSonIndex = 2*curIndex;
            // 最小子节点下标默认值: 左孩子下标
            int minSonIndex = leftSonIndex;
            int rightSonIndex = leftSonIndex+1;
            /**
             * 1、这个判断的是存在右孩子        rightSonIndex<=headSize
             * 2、判断如果右孩子比左孩子小       headArr[leftSonIndex]>headArr[rightSonIndex]
             * 3、如果右孩子比左孩子还小,最小孩子就是右孩子  minSonIndex = rightSonIndex
             */
            if (rightSonIndex<=headSize && headArr[leftSonIndex]>headArr[rightSonIndex]) minSonIndex = rightSonIndex;
            // 如果当前节点比最小孩子节点大(不满足小根堆) 则节点交换位置
            if (headArr[curIndex] > headArr[minSonIndex]) {  // 如果最小孩子比当前节点小
                swap(headArr, curIndex, minSonIndex);
                // 交换之后 当前节点的下标也换了
                curIndex = minSonIndex;
            }else break;
        }
    }

主方法测试

public static void main(String[] args) {
        MyHead myHead = new MyHead(20);
        for (int i=0; i<10; i++) {
            Scanner sc = new Scanner(System.in);
            int num = sc.nextInt();
            myHead.put(num);
            for (int j=1; j<=myHead.headSize; j++) {
                System.out.print(myHead.headArr[j]+" ");
            }
            System.out.println();
        }
        for (int i=0; i<10; i++) {
            int minNum = myHead.pop();
            System.out.println("最小值为:"+minNum);
            for (int j=1; j<=myHead.headSize; j++) {
                System.out.print(myHead.headArr[j]+" ");
            }
            System.out.println();
        }
    }

Java中提供的优先队列

Java中的堆是用优先队列PriorityQueue实现的。默认创建一个小根堆,可以接受一个Comparator比较器,来创建最大堆。由于Comparator是一个函数接口,这里我们可以直接传入一个lambda表达式就能够自动创建Comparator对象。

Queue<Integer> minheap =new PriorityQueue<Integer>();//默认为最小堆
// 大根堆 (这种内部类的方式 比 lamda表达式的效率要高)
PriorityQueue<Integer> maxHead = new PriorityQueue<Integer>(new Comparator<Integer>() {
    @Override
    public int compare(Integer o1, Integer o2) {
        return o2-o1;
    }
});
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

coderzpw

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值