优先队列,堆

本文介绍了优先队列和堆数据结构,包括优先队列的Java实现,堆(最大堆)的概念、操作及数组实现,以及堆排序的算法步骤和Java实现。通过优先队列,可以在O(1)时间内获取最高优先级元素,而堆则是一种快速找到最大或最小值的数据结构。堆排序的时间复杂度为O(n log(n)),是不稳定的排序算法。
摘要由CSDN通过智能技术生成

普通的数据结构,如果我们想要寻找所存元素中的最大值或者最小值,需要挨个查找。而本章所学的优先队列和堆会按照优先级给元素排序,帮助我们以最快的速度O(1)获取优先级最高的元素。

优先队列

优先队列把优先级最高的元素设为链表的头节点,这样我们获取或删除优先级最高的元素只需要O(1)的时间复杂度,这么设计的代价就是牺牲插入的效率,每次插入一个新的元素时,我们都需要迭代链表,并找到合适的地方插入,这个时间复杂度往往是O(n)。

以下是优先队列支持的操作:

  • push:插入一个新的元素
  • pop:将优先级最高的元素弹出(删除)
  • peek:查看优先级最高的值

使用java实现优先队列

优先队列的定义和链表很相似,首先我们需要定义节点和PriorityQueue

public class PriorityQueue {
   

    class Node {
   
        int value;
        // priority 越大,优先级越高
        int priority;
        Node next;

        public Node(int value, int priority) {
   
            this.value = value;
            this.priority = priority;
        }
    }

    // 头结点
    Node header = null;
}

其中Node就是队列中的节点,包含value数组和优先级priority,如果希望数值大的节点优先级高,那么可以将priority的数值设为和value一样。反之,我们可以将priority设为数值的相反数,那么在此队列中,一个数值越小,优先级就越高。在PriorityQueue中,我们只需要记录一个头节点head即可。

push方法定义
    public void push(int value, int priority) {
   
        // 队列为空,将当前节点设置为头结点
        if (header == null) {
   
            header = new Node(value, priority);
            return;
        }

        // 队列不为空,需要找到一个正确的位置将节点插入
        Node node = new Node(value, priority);
        // 将元素插入到头结点
        if (header.priority < priority) {
   
            node.next = header;
            header = node;
            return;
        }
        Node current = header;
        while (current.next != null && current.next.priority > priority) {
   
            current = current.next;
        }
        node.next = current.next;
        current.next = node;
    }

在Push中,我们需要检查是否头节点为空,如果是,就将新的节点设置为头节点。否则我们迭代循环头节点,将新的节点插入一个特定位置,插入后之前节点的优先级都比新节点高,之后节点的优先级都比新节点小。

peek和pop方法定义
    /**
     * 弹出头结点
     *
     * @return
     */
    public Node pop() {
   
        if (header == null) {
   
            return null;
        }
        Node tmp = header;
        header = header.next;
        return tmp;
    }

    /**
     * 返回头结点
     *
     * @return
     */
    public Node peek() {
   
        return header;
    }

peek只需要返回头节点即可。pop只需要弹出head的值,并让head指向自己的下一个节点即可。

isEmpty方法定义

isEmpty只需要查看head是否为空:

    /**
     * 判断队列是否为空
     *
     * @return
     */
    public boolean isEmpty() {
   
        return header == null;
    }
方法复杂度分析
  • push: O(n)
  • pop: O(1)
  • peek: O(1)

堆(Heap)

堆(Heap)是一种可以迅速找到一堆数中的最大或者最小值的数据结构,二叉堆(binary heap)是堆的一种实现,计算机中一般使用数组存储二叉堆。

堆是一颗完全二叉树,堆中的节点满足以下的条件:一个节点的父节点优先级比自己高,而自己的子节点优先级比自己底。优先级可以根据数值的大小来决定。最常见的堆有以下两种类型:

  • 最大堆(Max Heap):根节点数值最大,所有父节点的数值比各自的子节点数值大或等于子节点,很多地方也叫大顶堆。
    最大堆

  • 最小堆(Min Heap):根节点数值最小, 父节点数值比其子节点数值小或等于子节点,很多地方也叫小顶堆。
    最小堆

最大堆(Max Heap)

最大堆的基本操作:

  • add: 将新元素插入堆
  • poll: 将根节点(数值最大的元素)删除
  • peek: 获取根节点的数值

在任何的时间点,最大堆都应该保持其特性:父节点的数值比所有子节点大。在插入新元素的时候,我们要遵循以下步骤:

  1. 在堆的最后新建一个节点,将数值赋予新节点。
  2. 将其节点和父节点比较。
  3. 如果新节点的数值比父节点大,调换父子节点的位置。
  4. 重复步骤2和3直到最大堆的特性被满足。

以下是删除根节点的步骤:

  1. 移除根节点
  2. 将最后一个节点移到根节点处
  3. 将子节点和父节点比较
  4. 如果父节点的数值比子节点小,替换父子节点
  5. 重复步骤3和4直到最大堆的特性被满足。
使用数组实现最大堆

因为堆是一颗完全二叉树,因此我们可以直接使用数组而不是链表来实现堆。

最大堆的基本定义

                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值