优先级队列(堆)

目录

优先级队列

堆的概念

堆的创建

堆的向下调整

堆的插入

完整代码


优先级队列

队列是一种先进先出的数据结构,有些时候操作的数据可能带有优先级,出队列时就需要优先级高的数据先出队列

在这种情况下,数据结构应该提供两个最基本的操作,一个是返回最高优先级对象,一个是添加新的对象。这种数 据结构就是优先级队列(Priority Queue)。

堆的概念

如果有一个关键码的集合K = {k0,k1, k2,...,kn-1},把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中,并满足:Ki = K2i+1 且 Ki >= K2i+2) i = 0,1,2...,则称为小堆(或大堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。

注意:

  • 已知孩子节点为i,则双亲节点为 (i-1)/2;
  • 已知双亲节点为i,左孩子:2*i+1;右孩子:2*i+2。

堆的创建

堆的向下调整

这里以大根堆为例来讲解堆的向下调整。

题目:对于集合{ 27,15,19,18,28,34,65,49,25,37 }中的数据,如果将其创建成大根堆呢?

首先我们要定义基本变量,来供使用。因为是对于集合中的数据进行创建大根堆,所以我们可以使用数组来进行。

java 复制代码
public class TestHeap {
    public int[] elem;
    public int usedSize;

    public TestHeap(){
        this.elem = new int[10];
    }
}

对于如何把数组中的数据放到实现堆的数组里,我们可以通过for循环来进行放置。

注意:这里是有两个数组。

java 复制代码
    public void intelem(int[] array){
        for (int i = 0; i < array.length; i++) {
            this.elem[i] = array[i];
            usedSize++;
        }
    }

接着我们就要开始创建堆了

java 复制代码
    public void createHeap(){
        for (int parent = (this.usedSize-1-1)/2; parent >= 0 ; parent--) {
            shifDown(parent, this.usedSize);//每棵树结束时候都给个10,如果接着调整的节点比10
                                            //大了,说明这棵树一定调整完了
        }
    }

主要的重心在于如何写出shifDown这个方法。

思路:

  1. 由上面我们能知道 child = parent*2+1。为了确保child的数组不越界,我们要确定循环条件。
  2. 因为是创建大根堆,所以要找到左右子树的最大值同根节点进行比较、交换。
  3. 关于break,这里因为当 前一个节点已经结束了,下面的节点也是结束的状态。
java 复制代码
 /**
     *
     * @param parent 每棵子树调整的起始位置
     * @param usedSize 判断 每棵子树 什么时候  调整结束
     */
    private void shifDown(int parent, int usedSize) {
        int child = 2*parent+1;
        while(child < usedSize){
            //找到左右子树的最大值
            if(child+1 < usedSize && elem[child] < elem[child+1]){
                child++;
            }
            if(elem[child] > elem[parent]){
               swap(elem,child,parent);
                parent = child;
                child = 2*parent+1;
            }else{
                break;
            }
        }
    }

    private void swap(int[] elem, int i ,int j){
        int tmp = elem[i];
        elem[i] = elem[j];
        elem[j] = tmp;
    }

通过Test测试类和调试,我们能看到大根堆创建成功了。

java 复制代码
public class Test {
    public static void main(String[] args) {
        int[] array = {27,15,19,18,28,34,65,49,25,37};
        TestHeap testHeap = new TestHeap();

        //把array的值赋值给testHeap
        testHeap.intelem(array);
        testHeap.createHeap();
}

创建的堆下图,大根堆。

堆的插入

堆的插入总共需要两个步骤:

  1. 先将元素放入到底层空间中(注意:空间不够时需要扩容)
  2. 将最后新插入的节点向上调整,直到满足堆的性质

其实这和上面的创建大根堆有些类似,但这里用到的是向上调整。

java 复制代码
    //插入
    public void push(int val){
        if(isFull()){
            elem = Arrays.copyOf(elem,2*elem.length);
        }
        elem[usedSize] = val;
        sitUp(usedSize);
        usedSize++;

    }

    public boolean isFull(){
        return elem.length == usedSize;
    }
}

这里的关键在于向上调整部分代码的编写。

java 复制代码
    private void sitUp(int child) {
        int parent = (child-1)/2;
        while(parent >= 0){
            if (elem[parent] < elem[child]){
                swap(elem,child,parent);
                child = parent;
                parent = (child-1)/2;
            }else{
                break;
            }
        }
    }

向上调整我们可以先确定孩子节点,最后一棵树的节点位置可以通过 useSize来确定,进而能确定双亲节点。

完整代码

TestHeap类

java 复制代码
import java.util.Arrays;

public class TestHeap {
    public int[] elem;
    public int usedSize;

    public TestHeap(){
        this.elem = new int[10];
    }

    public void intelem(int[] array){
        for (int i = 0; i < array.length; i++) {
            this.elem[i] = array[i];
            usedSize++;
        }
    }

    public void createHeap(){
        for (int parent = (this.usedSize-1-1)/2; parent >= 0 ; parent--) {
            shifDown(parent, this.usedSize);//没棵树结束时候都给个10,如果接着调整的节点比10大了。说明这棵树一定调整完了
        }
    }


    //alt+p+enter 直接生成

    /**
     *
     * @param parent 每棵子树调整的起始位置
     * @param usedSize 判断 每棵子树 什么时候  调整结束
     */
    private void shifDown(int parent, int usedSize) {
        int child = 2*parent+1;
        while(child < usedSize){
            //找到左右子树的最大值
            if(child+1 < usedSize && elem[child] < elem[child+1]){
                child++;
            }
            if(elem[child] > elem[parent]){
               swap(elem,child,parent);
                parent = child;
                child = 2*parent+1;
            }else{
                break;
            }
        }
    }

    //插入
    public void push(int val){
        if(isFull()){
            elem = Arrays.copyOf(elem,2*elem.length);
        }
        elem[usedSize] = val;
        sitUp(usedSize);
        usedSize++;

    }


    private void swap(int[] elem, int i ,int j){
        int tmp = elem[i];
        elem[i] = elem[j];
        elem[j] = tmp;
    }


    private void sitUp(int child) {
        int parent = (child-1)/2;
        while(parent >= 0){
            if (elem[parent] < elem[child]){
                swap(elem,child,parent);
                child = parent;
                parent = (child-1)/2;
            }else{
                break;
            }
        }
    }

    public boolean isFull(){
        return elem.length == usedSize;
    }
}

Test类

java 复制代码
public class Test {
    public static void main(String[] args) {
        int[] array = {27,15,19,18,28,34,65,49,25,37};
        TestHeap testHeap = new TestHeap();

        //把array的值赋值给testHeap
        testHeap.intelem(array);
        testHeap.createHeap();
        /*for (int i = 0; i < array.length; i++) {
            testHeap.push(array[i]);
        }
        testHeap.push(80);*/
    }
}
相关推荐
黑子哥呢?41 分钟前
安装Bash completion解决tab不能补全问题
开发语言·bash
青龙小码农1 小时前
yum报错:bash: /usr/bin/yum: /usr/bin/python: 坏的解释器:没有那个文件或目录
开发语言·python·bash·liunx
大数据追光猿1 小时前
Python应用算法之贪心算法理解和实践
大数据·开发语言·人工智能·python·深度学习·算法·贪心算法
Dream it possible!1 小时前
LeetCode 热题 100_在排序数组中查找元素的第一个和最后一个位置(65_34_中等_C++)(二分查找)(一次二分查找+挨个搜索;两次二分查找)
c++·算法·leetcode
夏末秋也凉1 小时前
力扣-回溯-46 全排列
数据结构·算法·leetcode
南宫生1 小时前
力扣每日一题【算法学习day.132】
java·学习·算法·leetcode
柠石榴1 小时前
【练习】【回溯No.1】力扣 77. 组合
c++·算法·leetcode·回溯
Leuanghing1 小时前
【Leetcode】11. 盛最多水的容器
python·算法·leetcode
qy发大财1 小时前
加油站(力扣134)
算法·leetcode·职场和发展
王老师青少年编程1 小时前
【GESP C++八级考试考点详细解读】
数据结构·c++·算法·gesp·csp·信奥赛