【算法】【只有自己看得懂系列】玩转二叉堆

二叉堆的性质(以最小堆为例)

  • 每个子节点必须小于等于根节点
  • 堆结构必须是一颗满二叉树

应用

  • 优先队列
  • 预排序

Java实现

package mairuis.algorithm.heap;

/**
 * 最小堆
 * 性质:
 * 1.每个子节点都小于等于其父节点
 *
 * @author Mairuis
 * @date 2019/5/23
 */
public class MinHeap<T extends Comparable<T>> {
    private Comparable[] array;
    private int size;

    public MinHeap(int size) {
        this.array = new Comparable[size];
    }

    public MinHeap(Comparable[] array) {
        this.array = array;
        this.size = array.length;
    }


    public void insert(T element) {
        //在尾部插入然后上浮该节点
        this.set(size + 1, element);
        this.size += 1;
        this.swim(size);
    }

    public T getMin() {
        return (T) array[0];
    }

    public void deleteMin() {
        //删除根节点,将最右边的节点赋值到根节点
        this.swap(1, size);
        this.set(size, null);
        size -= 1;
        //下沉该节点维护堆的性质
        this.sink(1);
    }

    private void set(int index, T v) {
        array[index - 1] = v;
    }

    private void swim(int node) {
        int x = node;
        int parent = node >> 1;
        //判断1:如果是根节点 node >> 1必定为0,parent != 0 以此实现终止
        //判断2:比较该节点与父节点,如果小于父节点则交换,维护性质
        while (parent != 0 && compare(x, parent)) {
            swap(x, parent);
            x = parent;
            parent = parent >> 1;
        }
    }

    private void sink(int node) {
        int least = node, root = node;
        //如果不是根节点则交换,然后递归的维护下一棵树
        while (root <= size) {
            //找到树中最大的节点
            int left = root << 1, right = (root << 1) + 1;
            if (left <= size && compare(left, root)) {
                least = left;
            }
            if (right <= size && compare(right, least)) {
                least = right;
            }
            if (least != root) {
                //将树中最小的节点与根交换
                swap(root, least);
                //循环维护下一棵树
                root = least;
            } else {
                break;
            }
        }
    }

    /**
     * 构建一个堆
     *
     * @param array
     * @param <T>
     * @return
     */
    public static <T extends Comparable<T>> MinHeap<T> buildHeap(Comparable<T>[] array) {
        MinHeap<T> heap = new MinHeap<>(array);
        //从size除以2开始,筛选掉叶子节点,然后从下往上递归的维护每棵树的堆性质
        for (int i = heap.size >> 1; i > 0; i -= 1) {
            heap.sink(i);
        }
        return heap;
    }

    /**
     * 堆排序
     *
     * @param array
     * @param <T>
     * @return
     */
    public static <T extends Comparable<T>> T[] heapSort(T[] array) {
        MinHeap<T> heap = buildHeap(array);
        for (int i = heap.size; i > 1; i -= 1) {
            //将最小元素和最后一个元素交换位置
            heap.swap(1, i);
            //维护size字段,以保证最小元素在堆外
            heap.size -= 1;
            //将新的根下沉维护堆性质
            heap.sink(1);
        }
        return (T[]) heap.array;
    }


    private boolean compare(int a, int b) {
        return less(a, b);
    }

    private boolean less(int a, int b) {
        return array[a - 1].compareTo(array[b - 1]) < 0;
    }

    private void swap(int a, int b) {
        Comparable temp = array[a - 1];
        array[a - 1] = array[b - 1];
        array[b - 1] = temp;
    }

    public static void main(String[] e) {
//        MinHeap<Integer> heap = new MinHeap<>(1000);
//        int[] array = Sort.generalIntegers(1000);
//        for (int i = 0; i < array.length; i++) {
//            heap.insert(array[i]);
//        }
//        for (int i = 0; i < heap.size; i++) {
//            System.out.println(heap.getMin());
//            heap.deleteMin();
//        }

//        Integer[] data = new Integer[]{1, 3, 2, 5, 4};
//        MinHeap<Integer> heap = buildHeap(data);
//        System.out.println(heap.getMin());
//        heap.deleteMin();
//        System.out.println(heap.getMin());
//        heap.deleteMin();
//        System.out.println(heap.getMin());
//        heap.deleteMin();
//        System.out.println(heap.getMin());
//        heap.deleteMin();
//        System.out.println(heap.getMin());
//        heap.deleteMin();
//
//        Integer[] array = heapSort(new Integer[]{2, 1, 3, 4, 5});
//        for (int i = 0; i < array.length; i++) {
//            System.out.println(array[i]);
//        }
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值