数据结构-二叉堆

package com.company.binaryHeapTree;

/**
 * 堆的基本API
 *
 * @param <E>
 */
public interface Heap<E> {
    int size(); // 元素的数量

    boolean isEmpty(); // 是否为空

    void clear(); // 清空

    void add(E element); // 添加元素

    E get(); // 获得堆顶元素

    E remove(); // 删除堆顶元素

    E replace(E element); // 删除堆顶元素的同时插入一个新元素

}

 

package com.company.binaryHeapTree;

import java.util.Arrays;
import java.util.Comparator;

/**
 * 设计背景:
 * 现在需要一种数据结构要满足如下条件:
 * 1、添加元素
 * 2、获取最大值
 * 3、删除最大值
 * 实现方案:
 * 1、动态数组/双向链表 时间复杂度分别为 O(n) O(n) O(n)
 * 2、有序动态数组、双向链表 时间复杂度分别为 O(1) O(1) O(1)
 * 3、BBST平衡二叉搜索树 时间复杂度分别为 O(logn) O(logn) O(logn)
 * 然而以上三种方式要么时间复杂度太大 要么全排序浪费性能 要么实现过于复杂
 * 因此需要思考一种更加合理的数据结构 ,那就是二叉堆 获取最大值 O(1) 添加元素O(logn) 删除元素O(logn)
 * 相关应用:
 * 1、TOP K 问题,从海量数据中找出前K个元素
 * 2、优先级队列
 * <p>
 * 堆的一个重要性质,任意节点的值总是 >= 或者 <= 子节点的值
 * 二叉堆的逻辑结构就是一棵完全二叉树,鉴于完全二叉树的一些特性,二叉堆底层可以用数组实现
 * <p>
 * 索引i的规律(n是元素数量)
 * 1、如果i = 0,那么它是根节点
 * 2、如果i > 0,那么它的父节点是floor((i-1)/2)
 * 3、如果2i + 1 <= n-1 那么他的做子节点的索引为 2i + 1
 * 4、如果2i + 1 > n-1 那么它无左子节点
 * 5、如果2i + 2 <= n-1 那么它的右子节点的索引为 2i + 2
 * 6、如果2i + 2 > n-1 那么它无右子节点
 */
public class BinaryHeapTree<E> implements Heap {

    private E[] elements;
    private static final int DEFAULT_CAPACITY = 10;
    private int size;
    protected Comparator<E> comparator;

    public BinaryHeapTree(Comparator<E> comparator) {
        this.elements = (E[]) new Object[DEFAULT_CAPACITY];
        this.comparator = comparator;
    }

    public int compare(E e1, E e2) {
        return comparator != null ? comparator.compare(e1, e2)
                : ((Comparable<E>) e1).compareTo(e2);
    }

    @Override
    public int size() {
        return size;
    }

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

    private void emptyCheck() {
        if (isEmpty()) {
            throw new IndexOutOfBoundsException("Heap is empty");
        }
    }

    @Override
    public void clear() {
        for (int i = 0; i < size; i++) {
            elements[i] = null;
        }
        size = 0;
    }

    @Override
    public void add(Object element) {
        elementNotNullCheck((E) element);
        dilatation(size + 1);
        elements[size++] = (E) element;
        siftUp(size - 1);
    }

    private void elementNotNullCheck(E e) {
        if (e == null) {
            throw new IllegalArgumentException("Element cannot be null");
        }
    }

    /**
     * 往堆中添加元素 不断地与父元素相比较 直到小于等于父元素
     *
     * @param index
     */
    private void siftUp(int index) {
        E element = elements[index];
        while (index > 0) {
            int parentIndex = (index - 1) >> 1;
            E parent = elements[parentIndex];
            if (compare(parent, element) > 0) break;
            elements[index] = parent;
            index = parentIndex;
        }
        elements[index] = element;
    }

    private void dilatation(int index) {
        int oldCapacity = elements.length;
        if (index == oldCapacity) {
            System.out.println("数组要扩容了");
            int newCapacity = oldCapacity + (oldCapacity >> 1);
            elements = Arrays.copyOf(elements, newCapacity);
        }
    }

    @Override
    public Object get() {
        emptyCheck();
        return elements[0];
    }

    @Override
    public Object remove() {
        emptyCheck();
        E top = elements[0];
        int lastIndex = --size;
        elements[0] = elements[lastIndex];
        elements[lastIndex] = null;
        siftDown(0);
        return top;
    }

    private void siftDown(int index) {
        E last = elements[index];
        int half = size >> 1;
        while (index < half) {//index必须是非叶子节点
            int childIndex = (index << 1) + 1;
            E child = elements[childIndex];
            int rightIndex = childIndex + 1;
            if (rightIndex < size && compare(child, elements[rightIndex]) < 0) {
                child = elements[childIndex = rightIndex];
            }
            if (compare(last, child) >= 0) break;
            elements[index] = child;
            index = childIndex;
        }
        elements[index] = last;
    }

    @Override
    public Object replace(Object element) {
        return null;
    }
}
package com.company.binaryHeapTree;

import java.util.Comparator;

public class Main {
    public static void main(String[] args) {
        BinaryHeapTree<Integer> heap = new BinaryHeapTree<>(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o1.compareTo(o2);
            }
        });
        heap.add(7);
        heap.add(9);
        heap.add(45);
        heap.add(7);
        heap.add(5);
        heap.add(1);
        heap.add(0);
        heap.add(2);
        heap.add(66);
        heap.add(4);
        while (!heap.isEmpty()) {
            System.out.println(heap.remove());
        }
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值