IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> JAVA实现优先级队列--堆 -> 正文阅读

[数据结构与算法]JAVA实现优先级队列--堆

目录

1.优先级队列和堆的概念

2.优先级队列的实现


1.优先级队列和堆的概念

1.1.什么是优先级队列??

我们都学过队列,队列是一种先进先出的数据结构,但有些情况下,操作的数据可能带有优先级,一般出队列时,可能需要优先级高的元素先出队列,这就是优先级队列。比如有时候我们在打游戏的时候,别人打电话给你,那么系统一定是先处理打进来的电话。

1.2.什么是堆??

简言之,堆其实就是一棵完全二叉树,它的底层是一个数组,数组中存储这棵完全二叉树层序遍历的结果,按种类分,它又分为大根堆和小根堆,请看下图:

  • 性质:

1.堆中的某个结点的值总是不大于或不于其父节点的值;

2.堆总是一棵完全二叉树;

? 所以完全二叉树的性质就可以拿来用:

  • 如果 i 为0,则 i 表示的结点为根节点,否则 i 结点的双亲结点为(i -?1)/ 2;
  • 如果 2 * i + 1 小于结点个数,则节点 i 的左孩子下标为 2 * i + 1,否则没有左孩子;
  • 如果 2 * i + 2 小于结点个数,则节点 i 的左孩子下标为 2 * i + 2,否则没有右孩子。

注意堆是一棵完全二叉树,它有着层序遍历的规则,所以采用顺序存储的方式来提高效率,而非完全二叉树是不适合使用顺序存储的方式来进行存储的,因为为了能够还原二叉树,空间中必须要存储空节点,就会导致空间利用率比较低。


2.优先级队列的实现

2.1创建大根堆

public class TestHeap {
    public int elem[];
    public int usedSize;
    public static int DEFAULT_SIZE = 10;

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

    public int[] createHeap(int[] array) {
        //准备数据
        for (int i = 0; i < array.length; i++) {
            this.elem[i] = array[i];
            this.usedSize++;
        }
        //创建大根堆
        for (int p = (this.usedSize - 1 - 1) / 2; p >= 0 ; p--) {
            //向下调整
            shiftDown(p, this.usedSize);
        }
        return this.elem;
    }
    private void shiftDown(int parent, int len) {
        //左孩子
        int child = 2 * parent + 1;
        //每一次调整的结束条件 --> child < len
        while(child < len) {
            //拿到左右孩子的最大值
            if(child + 1 < len && this.elem[child] < this.elem[child + 1]) {
                child++;
            }
            if(this.elem[child] > this.elem[parent]){
                swap(parent, child);
                //继续判断它子树是否调整
                parent = child;
                child = 2 * parent + 1;
            } else {
                //无需调整
                break;
            }
        }
    }
    private void swap(int parent, int child) {
        int tmp = this.elem[parent];
        this.elem[parent] = this.elem[child];
        this.elem[child] = tmp;
    }
}
  • 思路

  • ?时间复杂度

?1.向下调整的时间复杂度:

最坏情况就是调整完 0 这棵树,那么调整的次数就是完全二叉树的高度,此时时间复杂度为 O(log2^n);

2.建大根堆的时间复杂度:

分析建堆的时间复杂度,我们需要从它的思想层面去分析,不能果断的断定:

每次调整的时间为 O(log2^n),然后调整 n 次,所以时间复杂度为 n * (log2^n),这是错误的!


?假设这棵完全二叉树是一棵满二叉树,树的高度为 n ,那么我们只需要调整第 n 层以上的树(调整 1 -? n - 1层):


?2.2插入数据

   public void offerHeap(int val) {
        if(isFull()) {
            this.elem = Arrays.copyOf(this.elem, 2*this.elem.length);
        }
        //1.放在最后一个位置
        this.elem[this.usedSize] = val;
        //2.进行向上调整
        shiftUp(usedSize);
        //3.有效数据+1
        this.usedSize++;
    }
    private void shiftUp(int child) {
        //父节点
        int parent = (child - 1) / 2;
        while(child > 0) {
            if(this.elem[child] > this.elem[parent]) {
                swap(child,parent);
                //向上调整
                child = parent;
                parent = (child - 1) / 2;
            } else {
                break;
            }
        }
    } 
    private boolean isFull() {
        return this.usedSize == this.elem.length;
    }
  • 思路

1.将待插入的数据放在 usedSize 位置

2.从usedSize下标的数据向上调整


?2.3删除数据

    public int pollHeap() {
        if(isEmpty()) {
            throw new MyHeapIsEmptyException("优先级队列为空!");
        }
        int tmp = this.elem[0];
        //将最后一个数据与堆顶数据进行交换
        swap(usedSize-1,0);
        this.usedSize--;
        //向下调整
        shiftDown(0, this.usedSize);
        return tmp;
    }
    private boolean isEmpty() {
        return this.usedSize == 0;
    }
  • 思路

1.将最后一个数据与堆顶数据进行交换

3.将堆中有效数据个数减少一个

2.然后再进行向下调整


2.4获取堆顶元素

    public int peekHeap() {
        if(isEmpty()) {
            throw new MyHeapIsEmptyException("优先级队列为空!");
        }
        return this.elem[0];
    }

谢谢观看!!!

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-06-04 00:05:27  更:2022-06-04 00:05:29 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/30 1:24:38-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码