最大堆的实现

最大堆的实现 根节点从零开始编号


import java.util.ArrayList;
import java.util.List;

public class Maxheap {
    //保存元素的数组使用JDK动态数组
    private List<Integer> arr;
    //当前最大堆有效元素的个数
    private int size;

    public Maxheap() {
        this(10);
    }

    public Maxheap(int capacity) {
        this.arr = new ArrayList<>(capacity);
    }

    //接收任意数组调整成最大堆
    public Maxheap(int[] nums) {
        this.arr = new ArrayList<>(nums.length);
        for (int i : nums) {
            arr.add(i);
            size++;
        }
        //将最后一个非子叶节点不断向上调整为最大堆
        for (int i = father(size - 1); i >= 0; i--) {
            siftdown(i);
        }

    }

    public int peekMax() {
        if (isEmpty()) {
            throw new IllegalArgumentException("heap is empty!cannot peek!");
        }
        return arr.get(0);
    }

  //从下标k开始进行元素的下沉操作
     

    private void siftdown(int k) {
        //当前在子树
        while (leftChild(k) < size) {
            int j = leftChild(k);
            if (j + 1 < size && arr.get(j) < arr.get(j + 1)) {
                j = j + 1;
            }
            // 此时j一定对应了左右子树的最大值索引
            if (arr.get(k) >= arr.get(j)) {
                // 当前元素对应的k已经落到了最终位置
                break;
            } else {
                //当前元素k小于子树的最大值,将子树最大值交换上去
                seap(k, j);
                //继续向上判断
                k = j;
            }

        }
    }

    // 获取当前节点的父节点编号
    private int father(int k) {
        return (k - 1) >> 1;
    }

    // 获取当前节点的左子树节点编号
    private int leftChild(int k) {
        return (k << 1) + 1;
    }

    // 获取当前节点的右子树节点编号
    private int rightChild(int k) {
        return (k << 1) + 2;
    }

    public boolean isEmpty() {
        return size == 0;
    }

    @Override
    public String toString() {
        return arr.toString();
    }

    public void add(int val) {
        //默认尾插
        this.arr.add(val);
        size++;
        //进行元素上浮
        //此时size-1是最后一个有效元素
        siftup(size - 1);
    }

   
   // 移除当前最大堆的最大值并返回
   
    public int extractMax() {
        if (isEmpty()) {
            throw new IllegalArgumentException("heap is empty!cannot extract!");
        }
        int maxVal = arr.get(0);
        // 1.将当前最后一个元素覆盖到堆顶
        // arr[0] = arr[size - 1]
        arr.set(0, arr.get(size - 1));
        // 2.删除当前数组中的最后一个元素
        arr.remove(size - 1);
        size--;
        // 3.从根节点开始进行元素的下沉操作
        siftdown(0);
        return maxVal;
    }


 // 元素上浮操作,将索引为k的元素上浮使得当前完全二叉树仍然满足堆的性质
 
    private void siftup(int k) {
        //终止条件
        //1.k == 0没有父节点,当前元素已经到达最终位置
        // 2.arr[k] <= arr[parent[k]],当前元素已经到达最终位置
        // 继续条件 : 还存在父节点,且当前元素 > 父节点
        while (k > 0 && arr.get(k) > arr.get(father(k))) {
            seap(k, father(k));
            //继续向上判断
            k = father(k);
        }
    }

    private void seap(int i, int j) {
        int temp = arr.get(i);
        arr.set(i, arr.get(j));
        arr.set(j, temp);
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值