首页 > 其他分享 >数据结构第17节 最小堆

数据结构第17节 最小堆

时间:2024-07-09 12:27:37浏览次数:14  
标签:index 17 int 最小 smallest heap 数据结构 public size

最小堆(Min Heap)是一种特殊的完全二叉树数据结构,在这种结构中,对于任意节点,其值都小于或等于它的子节点的值。根节点是堆中的最小元素。最小堆常用于实现优先队列,以及堆排序算法。

在Java中,我们可以使用数组或ArrayList来实现最小堆,因为完全二叉树的特性允许我们通过简单的数学运算在数组中找到父节点和子节点的位置。

最小堆的基本操作:

  1. 插入元素:将新元素添加到数组的末尾,然后从下至上调整以保持最小堆的性质。
  2. 删除最小元素:移除数组的第一个元素(即堆顶),然后将最后一个元素移到堆顶,再从上至下调整以保持堆的性质。
  3. 获取最小元素:直接访问数组的第一个元素。

示例代码:

下面是一个简单的Java实现最小堆的示例:

import java.util.Arrays;

public class MinHeap {
    private int[] heap;
    private int size;

    public MinHeap(int capacity) {
        heap = new int[capacity];
        size = 0;
    }

    // 插入元素
    public void insert(int value) {
        if (size == heap.length) {
            throw new IllegalStateException("Heap is full");
        }
        heap[size] = value;
        siftUp(size);
        size++;
    }

    // 上浮操作,保持最小堆性质
    private void siftUp(int index) {
        while (index > 0) {
            int parentIndex = (index - 1) / 2;
            if (heap[parentIndex] > heap[index]) {
                swap(parentIndex, index);
                index = parentIndex;
            } else {
                break;
            }
        }
    }

    // 删除并返回最小元素
    public int extractMin() {
        if (size == 0) {
            throw new IllegalStateException("Heap is empty");
        }
        int min = heap[0];
        heap[0] = heap[size - 1];
        size--;
        siftDown(0);
        return min;
    }

    // 下沉操作,保持最小堆性质
    private void siftDown(int index) {
        int leftChildIndex = 2 * index + 1;
        int rightChildIndex = 2 * index + 2;
        int smallest = index;

        if (leftChildIndex < size && heap[leftChildIndex] < heap[smallest]) {
            smallest = leftChildIndex;
        }
        if (rightChildIndex < size && heap[rightChildIndex] < heap[smallest]) {
            smallest = rightChildIndex;
        }
        if (smallest != index) {
            swap(index, smallest);
            siftDown(smallest);
        }
    }

    // 交换两个元素
    private void swap(int i, int j) {
        int temp = heap[i];
        heap[i] = heap[j];
        heap[j] = temp;
    }

    // 打印堆的内容
    public void printHeap() {
        System.out.println(Arrays.toString(Arrays.copyOf(heap, size)));
    }
}

使用示例:

public class Main {
    public static void main(String[] args) {
        MinHeap heap = new MinHeap(10);
        heap.insert(10);
        heap.insert(1);
        heap.insert(15);
        heap.insert(5);
        heap.printHeap(); // 输出: [1, 5, 10, 15]
        System.out.println("Extracted min: " + heap.extractMin()); // 输出: Extracted min: 1
        heap.printHeap(); // 输出: [5, 10, 15]
    }
}

这段代码创建了一个最小堆,并提供了插入和删除最小元素的功能。注意,实际应用中可能需要处理堆满或空的情况,以及可能的异常情况。此外,上述代码未包含容量自动扩展的逻辑,实际使用时应考虑这一点。

为了使代码更加健壮和实用,我们可以添加以下功能:

  1. 自动扩展堆的容量:当插入元素导致堆溢出时,动态地增加堆的大小。
  2. 堆的初始化:提供一个构造函数接受一个数组,可以立即构建一个最小堆。
  3. 获取堆的大小和是否为空的方法

以下是完善后的代码:

import java.util.Arrays;

public class MinHeap {
    private int[] heap;
    private int size;
    private int capacity;

    public MinHeap(int capacity) {
        this.capacity = capacity;
        heap = new int[capacity];
        size = 0;
    }

    // 构造函数,接收一个数组,构建最小堆
    public MinHeap(int[] arr) {
        this(arr.length);
        for (int value : arr) {
            insert(value);
        }
    }

    public void insert(int value) {
        ensureCapacity();
        heap[size] = value;
        siftUp(size);
        size++;
    }

    private void ensureCapacity() {
        if (size == heap.length) {
            int newCapacity = heap.length * 2;
            heap = Arrays.copyOf(heap, newCapacity);
            capacity = newCapacity;
        }
    }

    public int extractMin() {
        if (size == 0) {
            throw new IllegalStateException("Heap is empty");
        }
        int min = heap[0];
        heap[0] = heap[size - 1];
        size--;
        siftDown(0);
        return min;
    }

    private void siftUp(int index) {
        while (index > 0) {
            int parentIndex = (index - 1) / 2;
            if (heap[parentIndex] > heap[index]) {
                swap(parentIndex, index);
                index = parentIndex;
            } else {
                break;
            }
        }
    }

    private void siftDown(int index) {
        int leftChildIndex = 2 * index + 1;
        int rightChildIndex = 2 * index + 2;
        int smallest = index;

        if (leftChildIndex < size && heap[leftChildIndex] < heap[smallest]) {
            smallest = leftChildIndex;
        }
        if (rightChildIndex < size && heap[rightChildIndex] < heap[smallest]) {
            smallest = rightChildIndex;
        }
        if (smallest != index) {
            swap(index, smallest);
            siftDown(smallest);
        }
    }

    private void swap(int i, int j) {
        int temp = heap[i];
        heap[i] = heap[j];
        heap[j] = temp;
    }

    public void printHeap() {
        System.out.println(Arrays.toString(Arrays.copyOf(heap, size)));
    }

    public int getSize() {
        return size;
    }

    public boolean isEmpty() {
        return size == 0;
    }
}

使用示例:

public class Main {
    public static void main(String[] args) {
        int[] arr = {10, 1, 15, 5};
        MinHeap heap = new MinHeap(arr);

        System.out.println("Initial heap:");
        heap.printHeap();

        System.out.println("\nExtracted min: " + heap.extractMin());
        System.out.println("Heap after extraction:");
        heap.printHeap();

        System.out.println("\nInserting 3:");
        heap.insert(3);
        heap.printHeap();
        
        System.out.println("\nHeap size: " + heap.getSize());
        System.out.println("Is heap empty? " + heap.isEmpty());
    }
}

这个版本的最小堆类现在可以处理动态容量扩展,初始化一个已有元素的堆,以及提供了一些额外的辅助方法。

让我们通过一个表格逐步演示如何使用上面定义的 MinHeap 类。我们将执行一系列操作,包括插入元素、提取最小元素、检查堆的状态等。

初始状态

IndexValue
0-
1-
2-
3-
4-
Size0

操作 1: 插入元素 10

IndexValue
010
1-
2-
3-
4-
Size1

操作 2: 插入元素 1

IndexValue
01
110
2-
3-
4-
Size2

操作 3: 插入元素 15

IndexValue
01
110
215
3-
4-
Size3

操作 4: 插入元素 5

IndexValue
01
15
210
315
4-
Size4

操作 5: 提取最小元素

提取后,堆中最小元素(1)被删除,最后一个元素(15)被移动到堆顶,并进行下沉操作以保持堆的性质。

IndexValue
015
15
210
3-
4-
Size3

进行下沉操作后:

IndexValue
05
110
215
3-
4-
Size3

操作 6: 插入元素 3

IndexValue
03
15
210
315
4-
Size4

操作 7: 检查堆的大小和是否为空

  • 堆的大小: 4
  • 堆是否为空: false

通过这个步骤,我们可以清楚地看到 MinHeap 类是如何管理元素的插入、删除和维护堆的性质的。

标签:index,17,int,最小,smallest,heap,数据结构,public,size
From: https://blog.csdn.net/hummhumm/article/details/140291970

相关文章

  • 数据结构第18节 散列表
    散列表(HashTable),也称为哈希表,是一种数据结构,它使用哈希函数将键映射到数组的一个索引位置,从而可以快速地插入、查找和删除数据。散列表的核心在于哈希函数和解决冲突的策略。在Java中,散列表的实现通常涉及以下几个关键部分:哈希函数:用于将键转换为数组索引。解决冲突:多个......
  • 数据结构——二叉树之c语言实现堆与堆排序
    目录前言:1.二叉树的概念及结构1.1特殊的二叉树 1.2二叉树的存储结构  1.顺序存储2.链式存储 2.二叉树的顺序结构及实现 2.1堆的概念   ​编辑2.2堆的创建3.堆的实现3.1堆的初始化和销毁 初始化:销毁: 插入:向上调整:删除: 向下调整: 堆顶元素......
  • Hadoop-17 Flume 介绍与环境配置 实机云服务器测试 分布式日志信息收集 海量数据 实时
    章节内容上一节我们完成了:HiveServer2的介绍和配置安装修改core-sizehdfs-site实现集群的启动Beeline简单上手HCatalog简单上手背景介绍这里是三台公网云服务器,每台2C4G,搭建一个Hadoop的学习环境,供我学习。之前已经在VM虚拟机上搭建过一次,但是没留下笔记,这次......
  • 【Redis 理论与实践学习】 一、Redis的数据结构:4.Set类型
    文章目录简介Set和List的区别常用命令增删改查类命令添加元素移除元素判断元素是否存在获取集合大小获取集合所有成员随机获取元素随机移除并返回元素运算操作命令集合间操作集合间操作并存储应用场景博客点赞用户点赞操作公众号共同关注用户关注集合共同关注查询......
  • Python数据结构详解:列表、字典、集合与元组的使用技巧
    前言哈喽,大家好!今天我要和大家分享的是关于Python中最常用的数据结构:列表、字典、集合和元组的使用技巧。你有没有遇到过在处理数据时,不知道该用哪种数据结构来存储和操作数据的情况呢?别担心,今天这篇文章就来帮你搞定这些问题,让你在数据处理上更加得心应手。最后,别忘了关......
  • 【数据结构】—— 单链表(single linked list)
    文章目录1、单链表的定义优点和缺点单链表的构成2、单链表的创建初始化:3、单链表的接口实现打印尾插头插尾删头删查找在指定位置之前插入在指定位置之后插入删除指定位置的节点删除指定位置之后的节点销毁链表4、源代码1、单链表的定义单链表(SinglyLinkedList......
  • 高效维护区间之和/区间最值的数据结构(一)——树状数组
    高效维护区间之和/区间最值的数据结构(一)——树状数组树状数组的核心思想:分治。将数组以二叉树的形式进行维护区间之和。设aaa为原数组,......
  • C++数据结构底层实现算法
    1.vector底层数据结构为数组,支持快速随机访问2.list底层数据结构为双向链表,支持快速增删3.deque底层数据结构为一个中央控制器和多个缓冲区,详细见STL源码剖析P146,支持首尾(中间不能)快速增删,也支持随机访问deque是一个双端队列(double-endedqueue),也是在堆中保存内容的.每个......
  • 基于STM32设计的智能台灯(HC05蓝牙控制)179
    基于STM32设计的智能台灯(HC05蓝牙控制)(179)文章目录一、前言1.1项目介绍【1】开发背景【2】项目实现的功能【3】项目硬件模块组成1.2设计思路【1】整体设计思路【2】整体构架1.3项目开发背景【1】选题的意义【2】可行性分析【3】参考......
  • 数据结构第16节 最大堆
    最大堆是一种特殊的完全二叉树数据结构,其中每个父节点的键值都大于或等于其子节点的键值。在Java中,最大堆通常用于实现优先队列,堆排序算法,或者在需要快速访问最大元素的应用场景中。让我们通过一个具体的案例来说明最大堆的使用和实现:假设我们正在开发一个系统,用于实时分析......