Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >数据结构--堆

数据结构--堆

作者头像
良辰美景TT
发布于 2018-10-08 09:20:24
发布于 2018-10-08 09:20:24
58800
代码可运行
举报
运行总次数:0
代码可运行

堆有两个特性:

  • 堆是一个完全二叉树
  • 堆中所有父节点都大于(最大堆)或者小于(最小堆)子结点。 在一般的实现中,我们可以用数组来存储堆中的元素,数组的索引用于实现结点左右孩子的查找。 最小堆的实现代码如下:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * 
 * 功能描述: 最小堆的实现
 * 
 * @version 2.0.0
 * @author zhiminchen
 */
public class MinHeap<E extends Comparable<E>> {

    // 用于存储数据E对象
    private E[] data;
    // 当前数组已经存储了多少个数据
    private int size;

    public MinHeap(int capacity) {
        data = (E[]) new Comparable[capacity];
        size = 0;
    }

    public MinHeap() {
        this(16);
    }

    /**
     * 传入一个array数组,构造堆
     * 
     * @param array
     */
    public MinHeap(E[] array) {
        data = (E[]) new Comparable[array.length];
        // 将array数据复制到data数组中
        for (int i = 0; i < data.length; i++) {
            data[i] = array[i];
        }
        size = array.length;
        // 对堆中非叶子结点做siftDown操作, 这样堆的特性就维护好了
        for (int i = parent(array.length - 1); i >= 0; i--) {
            siftDown(i);
        }
    }

    /**
     * 
     * 功能描述: 堆是否为空的方法
     * 
     * @return boolean
     * @version 2.0.0
     * @author zhiminchen
     */
    public boolean isEmpty() {
        return size == 0;
    }

    /**
     * 
     * 功能描述: 返回当前堆的大小
     * 
     * @return int
     * @version 2.0.0
     * @author zhiminchen
     */
    public int size() {
        return size;
    }

    /**
     * 
     * 功能描述: 得到index的父亲结点
     * 
     * @param index
     * @return int
     * @version 2.0.0
     * @author zhiminchen
     */
    private int parent(int index) {
        if (index == 0)
            throw new IllegalArgumentException("index-0 doesn't have parent.");
        return (index - 1) / 2;
    }

    /**
     * 
     * 功能描述: 得到index的左孩子结点
     * 
     * @param index
     * @return int
     * @version 2.0.0
     * @author zhiminchen
     */
    private int left(int index) {
        return 2 * index + 1;
    }

    /**
     * 
     * 功能描述: 得到index下的右孩子结点
     * 
     * @param index
     * @return int
     * @version 2.0.0
     * @author zhiminchen
     */
    private int right(int index) {
        return 2 * index + 2;
    }

    /**
     * 
     * 功能描述: 往堆中增加元素element
     * 
     * @param element void
     * @version 2.0.0
     * @author zhiminchen
     */
    public void add(E element) {
        if (size >= data.length) {
            resize(data.length * 2);
        }

        data[size] = element;

        siftUp(size);
        size++;
    }

    /**
     * 
     * 功能描述: 删除堆顶的元素,并返回
     * 
     * @return E
     * @version 2.0.0
     * @author zhiminchen
     */
    public E remove() {
        if (size <= 0) {
            return null;
        }
        E ret = data[0];
        // 将数组的最后一个元素放到队列的头
        data[0] = data[size - 1];
        data[size - 1] = null;
        // 对size进行维护
        size--;
        // 对零位的数据进行下沉操作, 以保持堆的特性
        siftDown(0);
        return ret;
    }

    /**
     * 
     * 功能描述: 查看堆中最小的元素
     * 
     * @return E
     * @version 2.0.0
     * @author zhiminchen
     */
    public E findMin() {
        if (size == 0)
            throw new IllegalArgumentException("Can not findMin when heap is empty.");
        return data[0];
    }

    /**
     * 
     * 功能描述: 对index的元素进行下沉操作,以保持推的特性
     * 
     * @param index void
     * @version 2.0.0
     * @author zhiminchen
     */
    private void siftDown(int index) {
        int left = left(index);
        // 递归退出条件 left>=size说明当前节点已经是叶子节点了
        if (left >= size) {
            return;
        }
        // 假设index的左节点是最小的节点
        E min = data[left];
        // 如果index节点有右孩子并且右孩子比左孩子还小, index结点需要跟最小的节点进行交换
        if (left + 1 < size && min.compareTo(data[left + 1]) > 0) {
            min = data[left + 1];
            left = left + 1;
        }
        // 当index节点的数据比最小的节点还大的时候,则进行交换,否则结束
        if (data[index].compareTo(min) > 0) {
            swap(index, left);
            siftDown(left);
        }
    }

    /**
     * 
     * 功能描述: 对index元素进行上浮操作, 以维持队的特性
     * 
     * @param size2 void
     * @version 2.0.0
     * @author zhiminchen
     */
    private void siftUp(int index) {
        // 递归退出的条件
        if (index <= 0) {
            return;
        }
        // index节点比父亲节点小, 则进行上浮
        if (data[index].compareTo(data[parent(index)]) < 0) {
            swap(index, parent(index));
            // 递归调用,继续上浮
            siftUp(parent(index));
        }
    }

    /**
     * 
     * 功能描述: 交换索引为a, b的数据
     * 
     * @param a
     * @param b void
     * @version 2.0.0
     * @author zhiminchen
     */
    private void swap(int a,
                      int b) {
        E temp = data[a];
        data[a] = data[b];
        data[b] = temp;
    }

    /**
     * 
     * 功能描述: 对堆进行扩容
     * 
     * @param capacity void
     * @version 2.0.0
     * @author zhiminchen
     */
    private void resize(int capacity) {
        E[] temp = (E[]) new Object[capacity];
        for (int i = 0; i < data.length; i++) {
            temp[i] = data[i];
        }
        data = temp;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(String.format("heap size : %d capacity : %d ", size, data.length));
        sb.append("[");
        for (int i = 0; i < size; i++) {
            sb.append(data[i]);
            if (i != size - 1) {
                sb.append(", ");
            }
        }
        sb.append("]");
        return sb.toString();
    }

    public static void main(String[] args) {
        Random random = new Random();
        int n = 100;
        Integer array[] = new Integer[n];
        for (int i = 0; i < 100; i++) {
            array[i] = random.nextInt(Integer.MAX_VALUE);
        }

        MinHeap<Integer> heap = new MinHeap<Integer>(array);

        System.out.println(heap);

        List<Integer> list = new ArrayList<Integer>();
        while (!heap.isEmpty()) {
            list.add(heap.remove());
        }

        for (int i = 1; i < list.size(); i++) {
            if (list.get(i - 1) > list.get(i)) {
                throw new RuntimeException();
            }
        }

    }
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018.09.27 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
数据结构--线段树
  线段树用于处理区间数据的更新与查询问题,不考虑往区间中增加与删除数据的,主要用于统计数据方面的需求,在更新与查询的时间复杂度都为logn级别。线段树不属于完全二叉树,但属于平衡二叉树。
良辰美景TT
2018/10/08
3800
数据结构--线段树
数据结构之堆
有没有更优的数据结构?使用堆,可以使得获取最大值的时间复杂度为O(1)、删除最大值和添加元素的时间复杂度为O(logn)。
崔笑颜
2020/07/03
4880
二叉堆【转】
我们把二叉堆的根节点称之为堆顶。根据二叉堆的特性,堆顶要嘛是整个堆中的最大元素,要嘛是最小元素。
233333
2019/09/25
4340
二叉堆【转】
数据结构-队列
队列(queue)在计算机科学中,是一种先进先出的线性表。 它只允许在表的前端进行删除操作,而在表的后端进行插入操作。进行插入操作的端称为队尾,进行删除操作的端称为队头。队列中没有元素时,称为空队列。
杨小杰
2019/06/03
2960
数据结构——二叉堆
首先需要了解三个函数。这三个函数可以通过索引检索出父节点,也可以通过父节点的索引检索出子节点。例如下面一个最小二叉堆,可用数组的表示:
多云转晴
2020/03/28
5020
Java数据结构与算法解析(十四)——二叉堆
二叉堆是完全二元树或者是近似完全二元树,按照数据的排列方式可以分为两种:最大堆和最小堆。 最大堆:父结点的键值总是大于或等于任何一个子节点的键值;最小堆:父结点的键值总是小于或等于任何一个子节点的键值。
老马的编程之旅
2022/06/23
3580
Java数据结构与算法解析(十四)——二叉堆
数据结构之数组
1、数据结构研究的是数据如何在计算机中进行组织和存储,使得我们可以高效的获取数据或者修改数据。
别先生
2020/03/19
6490
【数据结构与算法】堆
,总的交换次数为 $$ \begin{aligned} & 4 * 0 + 2 * 1 + 1 * 2 \
程序员波特
2024/09/27
960
【数据结构与算法】堆
最小堆与索引堆
我们先来完成一个最小堆,采用JDK的ArrayList作为底层数据结构。关于堆的概念请参考数据结构整理 中最大堆的部分
算法之名
2020/10/26
9560
【数据结构】栈的基本实现
MaybeHC
2024/04/23
930
【数据结构】栈的基本实现
数据结构-数组
---- 数据结构-数组 数组 数据结构中最基本的一个结构就是线性结构,而线性结构又分为连续存储结构和离散存储结构。所谓的连续存储结构其实就是数组。 优点:查询较快如果知道坐标可以快速去地存取 缺点:删除慢,大小固定 二次封装数组的增删改查 基类的定义 定义一个工具类名称-Array 接受的参数包括基本类型和自定义类型(用泛型来接受,基本类型用包装类) 自定义属性两个:size用来表示数组的大小,data用来表示一个准确的集合 概念区分:size表示数组的大小,capacity表示数组容量的大小 构造函
杨小杰
2019/06/03
1.1K0
数据结构--堆的深度解析
堆(Heap)是一种非常重要的非线性数据结构,广泛应用于各种算法和问题解决中,如优先队列、堆排序、Top-k 问题等。本文将深入解析堆的定义、类型、操作、应用及其优缺点。
平凡之路.
2024/10/09
6650
数据结构--堆的深度解析
数据结构--堆 Heap
堆排序代码见:https://blog.csdn.net/qq_21201267/article/details/80993672#t7
Michael阿明
2021/02/20
3190
数据结构--堆 Heap
数据结构之堆
1、优先队列,本身就是一种队列。普通队列,先进先出,后进后出。优先队列,出队顺序和入队顺序无关,和优先级有关,优先级高者先得,优先级高的先出队。
别先生
2020/03/20
6490
TypeScript实现二叉堆
二叉堆是计算机科学中一种非常著名的数据结构,由于它能高效、快速地找出最大值和最小值因此常被用于优先队列和堆排序算法。
神奇的程序员
2022/04/10
6240
TypeScript实现二叉堆
Java堆结构PriorityQueue完全解析
在堆排序这篇文章中千辛万苦的实现了堆的结构和排序,其实在Java 1.5版本后就提供了一个具备了小根堆性质的数据结构也就是优先队列PriorityQueue。下面详细了解一下PriorityQueue到底是如何实现小顶堆的,然后利用PriorityQueue实现大顶堆。
全栈程序员站长
2022/08/11
8040
Java堆结构PriorityQueue完全解析
C++那些事之手写二叉堆强化模板函数及比较操作
本节重点带大家一起写一个二叉堆,并基于二叉堆实现优先队列,同时练习C++的模板类以及比较操作。
公众号guangcity
2020/07/02
6240
数据结构之优先队列
1、优先队列的底层实现可以使用最大堆进行实现,由于优先队列本身就是一个队列,所以可以复用队列的接口。
别先生
2020/03/19
3650
数据结构基础-优先队列和堆
优先队列可以看做队列的一种,区别在于,在优先队列中,元素进入队列的顺序可能与其被操作的顺序不同。他支持插入(Insert)和删除最小值(DeleteMin)操作(返回并删除最小元素)或删除最大值(DeleteMax)操作(返回并删除最大元素)。
1025645
2019/03/04
3850
数据结构基础-优先队列和堆
前端学数据结构与算法(七): 从零实现优先队列-堆及其应用
为什么说树结构是01世界里最重要的数据结构,因为只要调整一下节点的存储顺序或枝杈多少,解决问题的类型就可以完全不同。本章介绍的堆也是二叉树的一种,与二叉搜索树想比,只是改变了节点存放值的规则,它遵循的规则就是每个父节点的值必须大于或等于孩子节点的值,这种数据结构是二叉堆,也可以叫它优先队列。
飞跃疯人院
2020/10/07
3540
相关推荐
数据结构--线段树
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验