数据结构与算法之优先队列<九>

本文介绍了优先队列的概念及其应用,如数据压缩、最短路径等,并详细讲解了如何使用二叉堆来实现优先队列,包括插入、删除最大值等关键操作。

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

什么是优先队列
快速得找到元素的最大或最小值。为了实现这种数据结构
优先队列便孕育而生。优先队列或ADT是一种数据结构,支持插入和删除最小值或最大值并返回最大值或最小值得操作。

优先队列的应用
1.数据压缩(赫夫曼编码)
2.最短路径
3.最小生成树
4.选择问题:查找第K个最小元素

优先队列的实现
1.有序/无序数组实现
2.有序/无序链表实现
3.二叉树实现
4.二叉堆实现

主要介绍二叉堆的实现
二叉堆是一棵具有特殊性质的二叉树。
基本要求是所有节点必须大于或等于(小于或等于)其孩子节点
并且应该是一棵完全二叉树

二叉堆的实现


/*
 * 优先队列是至少允许下列两种操作的数据结构
 * insert(插入) deleteMin(删除最小) 
 * 优先队列的工作是 找出 返回 删除 优先队列中的最小或最大元素
 * 
 * 完全二叉堆实现优先队列
 * 利用完全二叉树的紧凑性将完全二叉树转化为数组形式
 */
public class BinaryHeap<T extends Comparable<? super T>> {
    // 堆
    private T[] heap;
    // 当前大小
    private int currentSize;
    // 默认大小
    private final static int DEFAULT_SIZE = 10;

    public BinaryHeap() {
        this(DEFAULT_SIZE);
    }

    // 打印二叉堆
    public void printHeap() {
        for (int i = 0; i < currentSize; i++)
            System.out.print(this.heap[i] + ",");
    }

    @SuppressWarnings("unchecked")
    public BinaryHeap(int size) {
        heap = (T[]) new Comparable[size];
    }

    // 将一个数组转化为二叉堆
    @SuppressWarnings("unchecked")
    public BinaryHeap(T[] items) {
        currentSize = items.length;
        heap = (T[]) new Comparable[(currentSize + 2) * 11 / 10];
        System.arraycopy(items, 0, heap, 0, items.length);
        bulidHeap();
    }

    /*
     * 对外开放的方法
     */

    // 插入堆
    public void insert(T t) {
        // 数据临界 扩一倍
        if (currentSize == heap.length)
            enlargeArray(heap.length * 2);
        // 当前数量加一
        currentSize++;
        // 插入节点的序号
        int i = currentSize - 1;
        while (i > 0 && t.compareTo(heap[(i - 1) / 2]) > 0) {
            // 插入数据大于其父节点的数据
            heap[i] = heap[(i - 1) / 2];
            // 下一个父节点
            i = (i - 1) / 2;
        }
        heap[i] = t;
    }

    // 找到最大值
    public T findMax() {
        if (currentSize > 0)
            return heap[0];
        return null;

    }

    // 删除最大值
    public T deleteMax() {
        T t = null;
        if (currentSize > 0) {
            t = heap[0];
            // 将最后一个元素替代第一个
            heap[0] = heap[currentSize - 1];
            currentSize--;
            percolateDown(0);
        }
        return t;
    }

    /*
     * 私人方法
     */

    // 下滤 (先找到孩子的最大值在与小于孩子的父节点互换)
    private void percolateDown(int hole) {
        // 判断节点是否有孩子
        int left = hole * 2 + 1;
        T temp;
        // 如果左孩子存在
        if (left < currentSize) {
            // 如果右孩子存在
            if (left + 1 < currentSize) {
                // 若右孩子大于左孩子互换
                if (heap[left + 1].compareTo(heap[left]) > 0) {
                    temp = heap[left + 1];
                    heap[left + 1] = heap[left];
                    heap[left] = temp;
                }
            }
            // 如果左节点大于父节点 互换
            if (heap[left].compareTo(heap[hole]) > 0) {
                temp = heap[hole];
                heap[hole] = heap[left];
                heap[left] = temp;
            }
        }
    }

    // 建立二叉堆
    public void bulidHeap() {
        // 调整所有节点 (currentSize表示当前堆中元素个数)
        for (int i = (currentSize - 2) / 2; i >= 0; i--) {
            percolateDown(i);
        }
    }

    // 动态扩充数组变为原来的两倍
    @SuppressWarnings("unchecked")
    private void enlargeArray(int newSize) {
        // 保存旧数据
        T[] temp = heap;
        // 扩一倍
        heap = (T[]) new Comparable[2 * heap.length];
        // 导入旧数据
        System.arraycopy(temp, 0, heap, 0, temp.length);
    }
}

至此,优先队列的基础介绍完毕。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值