算法与数据结构(十一)最大堆

二叉堆:

  • 是一个完全二叉树
  • 堆中的每个节点总是大于等于(或小于等于)子节点,对应的就是最大最小堆

可以用数组存储二叉堆

索引和节点之间的对应关系,索引从0开始

  • 给定一个索引可以知道这个索引的父节点索引,parent(i) = (i-1)/2
  • 给定一个索引可以知道这个索引的左子树的索引,leftChild(i) = 2*i +1
  • 给定一个索引可以知道这个索引的右子树的索引,rightChild(i) = 2*i +2

最大堆的实现

package com.yan.study.algorithm.maxheap;
import java.util.ArrayList;
import java.util.Collection;

//最大堆的实现
public class MaxHeap<E extends Comparable<E>> {

    // 使用动态数组保存堆中元素
    private ArrayList<E> data;

    public MaxHeap(int capacity){
        data = new ArrayList<>(capacity);
    }

    public MaxHeap(){
        data = new ArrayList<>();
    }

    //返回堆中元素的个数
    public int getSize(){
        return data.size();
    }
    //返回堆是否为空
    public boolean isEmpty(){
        return data.isEmpty();
    }
    //	 * 返回给定下标为index的节点的父节点下标值
    public int parent(int index){

        if(index == 0){

            throw  new IllegalArgumentException("索引0没有父节点");
        }

        return (index-1)/2;

    }
    //	 * 返回给定下标为index的节点的左子树下标值

    public int leftChild(int index){

        return 2 * index +1;

    }
    //返回给定下标为index的节点的右子树下标值
    public int rightChild(int index){
        return 2 * index +2;

    }
    //添加操作
    public void add(E e){
        data.add(e);//把这个元素添加到队尾
        siftUp(data.size()-1);//也就是最好一个元素上浮
    }

    //节点上浮
    private void siftUp(int index) {
        // 不是根节点, 且当前节点大于父节点时, 和父节点交换位置
        while(index!=0 && data.get(index).compareTo(data.get(parent(index))) > 0){

            swap(index, parent(index));

        }

    }
    //交换data位置
    private void swap(int first, int second) {

        E temp = data.get(first);
        data.set(first, data.get(second));
        data.set(second, temp);
    }
    //寻找最大元素
    public E findMax(){
        if (data.isEmpty()) {
            throw new IllegalArgumentException("当前堆为空, 无最大值");
        }
        return data.get(0);
    }
    //取出最大元素
    public E extractMax(){

        E ret = findMax();
        // 将最大值和最后一个叶子节点交换位置, 即用最后一个叶子节点替换了根节点
        swap(0, data.size() -1);
        // 删除最后一个叶子节点, 即删除了最大值
        data.remove(data.size() - 1);
        // 现在的根节点下沉
        siftDown(0);
        return ret;
    }


    //节点下沉
    private void siftDown(int index) {

        while (leftChild(index) < data.size()) {
            // 用于和index节点进行比较的节点, 先默认为左孩子节点
            int swapIndex = leftChild(index);
            /*
             * swapIndex + 1 < data.size表示右孩子也不为空
             * 右孩子节点值大于左孩子时, 使用右子树与当前节点进行比较
             */
            if (swapIndex + 1 < data.size() && data.get(swapIndex + 1).compareTo(data.get(swapIndex)) > 0) {
                // 右孩子下标进行替换, 这里也可以直接写成swapIndex ++;
                swapIndex = rightChild(index);
            }

            if (data.get(swapIndex).compareTo(data.get(index)) > 0) {
                swap(index, swapIndex);
                index = swapIndex;
            } else {
                return;
            }

        }
    }

	 // 替换根节点
    public E replace(E e){
        E ret = findMax();
        // 替换根节点
        data.set(0, e);
        // 根节点下沉
        siftDown(0);
        return ret;
    }

    /**
     * Heapify方式将集合中的元素添加到最大堆中
     * @param collection
     * 首先将数组当成一个完全二叉树
     *
     * 找到最后一个非叶子节点, 方法是根据最后一个元素计算其父节点
     *
     * 从最后一个非叶子节点之前的节点都执行Sift Down操作
     */
    public MaxHeap(Collection<E> collection){
        data = new ArrayList<>(collection);
        for(int i = parent(data.size() -1); i >= 0; i--){
            siftDown(i);
        }
    }

}

参考大神博客https://blog.csdn.net/love905661433/article/details/82989404

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值