Java实现二叉堆

本文介绍了堆这种特殊的数据结构,特别是完全二叉树的概念。堆分为非递减的父结点和非递增的子结点。讨论了堆的上浮和下沉操作,以及插入元素和删除最大元素的操作。内容包括Java代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

堆(Heap)是一类特殊的数据结构的统称。堆通常是一个可以被看做一棵完全二叉树的数组对象。
在二叉堆中,从任意结点向上,我们都能得到一列非递减的元素;从任意结点向下,我们都能得到一列非递增的元素。
在这里插入图片描述
在堆中有两个特殊的操作:

  1. 上浮(swim):

如果堆的有序状态因为某个结点变得比它父结点更大而打破,那么我们就需要进行上浮操作。

在这里插入图片描述

  1. 下沉(sink):

如果堆的有序状态因为某个结点变得比它的两个子节点或者其中之一更小而打破,那么我们就需要进行下沉操作。

在这里插入图片描述
插入元素:

将新元素添加到元素末尾,增加堆的大小并让这个新的元素上浮到合适的位置。

在这里插入图片描述
删除最大元素:

将数组最后一个元素和堆顶元素交换,减小数组大小并让这个元素下沉到合适的位置

在这里插入图片描述
具体实现代码如下:

/**
 * 大顶堆
 * @param <Item> 键
 */
public class MaxPQ <Item extends Comparable<Item>> {

    private int N;
    private Item[] pq;   //利用数组表示堆

    public MaxPQ() {
    	N = 0;
        pq = (Item[]) new Comparable[2];
    }

    /**
     * 调整数组大小
     * @param size  调整后的数组大小
     */
    private void resize(int size) {
        Comparable[] a = new Comparable[size];
        for (int i = 1; i <= N; i++) {
            a[i] = pq[i];
        }
        pq = (Item[]) a;
    }

    /**
     *
     * @param i 索引i
     * @param j 索引j
     * @return  索引为i的元素是否小于索引为j的元素
     */
    private boolean less(int i, int j) {
        return pq[i].compareTo(pq[j]) < 0;
    }

    /**
     * 交换元素
     * @param i 索引i
     * @param j 索引j
     */
    private void exch(int i, int j) {
        Item t = pq[i];
        pq[i] = pq[j];
        pq[j] = t;
    }

    /**
     * 上浮:如果某个结点比它的父结点要大,采取该操作
     * @param k 结点的位置
     */
    private void swim(int k) {
        while (k > 1) {
            if (less(k/2, k)) {
                exch(k/2, k);
                k = k/2;
            }
        }
    }

    /**
     * 下沉
     * @param k 结点的位置
     */
    private void sink(int k) {
        while (2*k <= N) {
            int j = 2*k;
            if (j < N && less(j, j+1)) {
                j++;
            }
            if (less(j, k)) {
                break;
            }
            exch(k, j);
            k = j;
        }
    }

    /**
     *
     * @return  堆是否为空
     */
    public boolean isEmpty() {
        return N == 0;
    }

    /**
     *
     * @return  堆中元素个数
     */
    public int size() {
        return N;
    }

    /**
     * 插入元素
     * @param Item   要插入的元素
     */
    public void insert(Item item) {
        if (N == pq.length-1) {
            resize(2*pq.length);
        }
        pq[++N] = item;
        swim(N);
    }

    /**
     * 删除并返回最大元素
     * @return  最大元素
     */
    public Item delMax() {
        if (N == pq.length/4) {
            resize(pq.length/2);
        }
        Item max = pq[1];
        exch(1, N--);
        pq[N+1] = null;
        sink(1);
        return max;
    }

    /**
     * 
     * @return  堆中最大值
     */
    public Item max() {
        return pq[1];
    }

    /**
     * 
     * @return  堆中最小值
     */
    public Item min() {
        int min = N;
        for (int i = N; i >= 1; i--) {
            if (less(i, min)) {
                min = i;
            }
        }
        return pq[min];
    }

    /**
     *
     * @param item  所要查找的元素
     * @return  该元素是否存在
     */
    public boolean contains(Item item) {
        for (int i = 1; i <= N; i++) {
            if (pq[i] == item) {
                return true;
            }
        }
        return false;
    }

    @Override
    public String toString() {
        StringBuilder s = new StringBuilder();
        for (int i = 1; i <= N; i++) {
            s.append(pq[i] + " ");
        }
        return s.toString();
    }

    public static void main(String[] args) {
        MaxPQ<Integer> maxPQ = new MaxPQ<>();
        for (int i = 1; i <= 24; i++) {
            maxPQ.insert(i);
        }
        System.out.println(maxPQ.toString());
        System.out.println(maxPQ.size());
        System.out.println(maxPQ.max());
        System.out.println(maxPQ.min());
        System.out.println(maxPQ.contains(0));
        maxPQ.delMax();
        System.out.println(maxPQ.toString());
    }

}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值