加强堆(java版本)

java中堆是用 java.util.PriorityQueue 实现的,支持新增向堆中添加元素、删除元素、弹出堆顶元素、查看堆顶元素、清空堆、获取堆大小、判读元素在不在堆中等功能。
但是却不支持修改堆中的元素,并继续保持堆结构。
下面我们就用手写一个堆,实现修改堆中元素,也依然能保持堆结构的加强堆

我们增加了反向索引表,记录每个元素在堆中的下标,这样可以在修改堆中元素后,以最小代价实现堆结构调整。

/**
 * Description:加强堆:
 * 普通堆:支持元素弹出、压入,获取对大小;,但是不能支持当堆内元素改变后,自动调整结构
 * 加强堆:支持:1)堆内元素改变后,自动调整结构;2)删除指定元素;
 *
 * @author LiuLei
 * @version 1.0
 * @date 2024/1/4 9:45
 */
public class HeapGreater<E> {
    private ArrayList<E> heapList;
    // 反向索引表,记录每个元素在数组中的下标,方便,元素变化,删除后,调整时以O(1)时间复杂度定位到元素
    private  HashMap<E, Integer> hashMap;
    private Comparator<? super E> comparator;
    private  int heapSize;

    public HeapGreater(Comparator<? super E> comparator) {
        this.heapSize = 0;
        this.heapList = new ArrayList<>();
        this.hashMap = new HashMap<>(heapSize);
        this.comparator = comparator;
    }

    public ArrayList<E> getHeapList() {
        ArrayList<E> list = new ArrayList<>(heapSize - 1);
         for (E e : heapList){
             list.add(e);
         }
         return list;
    }

    public int size(){
        return heapSize;
    }

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

    // 弹出堆顶元素
    public E pop(){
        E first = heapList.get(0);
        swap(0, heapSize - 1);
        heapList.remove(-- heapSize);
        hashMap.remove(first);
        heapify(0);

        return first;
    }

    public E peak(){
        return heapList.get(0);
    }

    // 压入元素
    public void add(E t){
        heapList.add(t);
        hashMap.put(t, heapSize);
        heapInsert(heapSize++);
    }

    // 删除指定元素
    public void remove(E t){
        // 末尾元素和要删除的指定元素互换,互换后,删除末尾
        Integer dIndex = hashMap.get(t);
        E last = heapList.get(heapSize - 1);

        // 移除被删除的元素
        heapList.remove(--heapSize);
        hashMap.remove(t);
        if(last != t){
            heapList.set(dIndex, last);
            hashMap.put(last, dIndex);
            resign(last);
        }
    }

    /**
     * 加强堆特有方法:对象改变后,自动实现堆结构调整
     */
    public void resign(E e){
        Integer index = hashMap.get(e);
        heapInsert(index);
        heapify(index);
    }

    // 向上找父节点PK,替换,直到顶部-pk对象是同一个节点
    public void heapInsert(int index){
        // 此处无须判断 index > 0,因为当index = 0时, (index - 1) / 2 = 0;
        while (comparator.compare(heapList.get(index), heapList.get((index - 1) / 2))< 0){
            swap(index, (index - 1) / 2);
            index = (index - 1) / 2;
        }
    }

    // 向下找子节点大的Pk, 替换,直到底部——无子节点
    public <E> void heapify(int index){
        int lChild = index * 2 + 1;
        int rChild = index * 2 + 2;

        while (lChild < heapSize || rChild < heapSize){
            int maxChildIndex;
            if( lChild < heapSize && rChild < heapSize){
                maxChildIndex = comparator.compare(heapList.get(lChild), heapList.get(rChild)) > 0? lChild : rChild;
            } else if(lChild < heapSize){
                maxChildIndex = lChild;
            } else {
                maxChildIndex = rChild;
            }
            if(comparator.compare(heapList.get(maxChildIndex), heapList.get(index)) <0){
                swap(index, maxChildIndex);
                index = maxChildIndex;
                lChild = index * 2 + 1;
                rChild = index * 2 + 2;
            } else {
                break;
            }
        }
    }

    private    void  swap(int index, int fatherIndex) {
        E temp1 =   heapList.get(index);
        E temp2 = heapList.get(fatherIndex);
        heapList.set(index, temp2);
        heapList.set(fatherIndex, temp1);

        // 反向索引表,记录index的变换
        hashMap.put(temp1, fatherIndex);
        hashMap.put(temp2, index);
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值