数据结构-堆排序

news2025/7/19 21:05:31

1.定义
 
-堆中每个节点的值都必须大于等于(或小于等于)其左右子节点的值。如果每个节点的值都大于等于其子节点的值,这样的堆称为大根堆(大顶堆);如果每个节点的值都小于等于其子节点的值,称为小根堆(小顶堆)。

2.堆的性质:
堆中某个节点的值总是不大于或不小于其父节点的值;

堆总是一棵完全二叉树;

3.堆的实现

3.1堆向下调整算法
现在我们给出一个数组,逻辑上看做一颗完全二叉树。我们通过从根节点开始的向下调整算法可以把它调整成一个小堆。向下调整算法有一个前提:左右子树必须是一个堆,才能调整

heap.h文件
// 确保头文件只被编译一次,避免重复包含导致的编译错误
#pragma once
// 包含标准库头文件,用于内存分配和动态内存管理,如 malloc、realloc、free 等函数
#include <stdlib.h>
// 包含断言库头文件,用于调试时检查条件是否为真,如果条件为假则程序终止
#include <assert.h>
// 包含布尔类型定义的头文件,使得代码可以使用 bool 类型
#include <stdbool.h>
// 包含标准输入输出库头文件,提供了基本的输入输出功能,如 printf、scanf 等
#include <stdio.h>

// 定义堆中数据的类型,这里将 int 类型重命名为 HPDataType,方便后续修改堆中数据的类型
typedef int HPDataType;

// 定义堆的结构体
typedef struct Heap
{
    // 指向堆数据数组的指针,用于存储堆中的元素
    HPDataType* a;
    // 堆中当前元素的数量
    int size;
    // 堆数组的容量,即当前分配的内存可以存储的元素个数
    int capacity;
} HP;

// 堆操作接口函数声明

// 初始化堆
// 参数:php 是指向堆结构体的指针,用于初始化堆的各项属性
void HeapInit(HP* php);

// 销毁堆
// 参数:php 是指向堆结构体的指针,用于释放堆所占用的内存资源
void HeapDestroy(HP* php);

// 向堆中插入一个元素
// 参数:php 是指向堆结构体的指针,x 是要插入的元素
void HeapPush(HP* php, HPDataType x);

// 删除堆顶元素
// 参数:php 是指向堆结构体的指针,该操作会移除堆中优先级最高的元素
void HeapPop(HP* php);     

// 获取堆顶元素
// 参数:php 是指向堆结构体的指针,返回堆顶元素的值
HPDataType HeapTop(HP* php);

// 判断堆是否为空
// 参数:php 是指向堆结构体的指针,返回一个布尔值,表示堆是否为空
bool HeapEmpty(HP* php);

// 获取堆中元素的数量
// 参数:php 是指向堆结构体的指针,返回堆中当前元素的个数
int HeapSize(HP* php);

插入元素(向上调整适合逐个插入元素构建小堆,向下调整适合对已有数据构建小堆且效率更高)

void HeapPush(HP* php, HPDataType x) 
{
    assert(php);
    // 扩容检查
    if (php->size == php->capacity) 
    {
        int newCapacity = php->capacity == 0 ? 4 : php->capacity * 2;
        HPDataType* tmp = (HPDataType*)realloc(php->a, newCapacity * sizeof(HPDataType));
        if (tmp == NULL) 
        {
            perror("realloc fail");
            exit(EXIT_FAILURE);  // 内存不足直接退出
        }
        php->a = tmp;
        php->capacity = newCapacity;
    }
    // 插入并调整
    php->a[php->size++] = x;
    AdjustUp(php->a, php->size - 1);
}

向上调整算法:

static void AdjustUp(HPDataType* a, int child) 
{
    int parent = (child - 1) / 2;
    while (child > 0) 
    {  // 小堆逻辑
        if (a[child] < a[parent]) 
        {
            Swap(&a[child], &a[parent]);
            child = parent;
            parent = (child - 1) / 2;
        }
        else 
        {
            break;
        }
    }
}

向下调整算法:

static void AdjustDown(HPDataType* a, int n, int parent) 
{
    int child = parent * 2 + 1;
    while (child < n) 
    {
        // 选择较小的子节点(小堆)
        if (child + 1 < n && a[child + 1] < a[child]) 
        {
            child++;
        }
        if (a[child] < a[parent]) 
        {
            Swap(&a[child], &a[parent]);
            parent = child;
            child = parent * 2 + 1;
        }
        else 
        {
            break;
        }
    }
}

4.建堆时间复杂度

因为堆是完全二叉树,而满二叉树也是完全二叉树,此处为了简化使用满二叉树来证明(时间复杂度本来看的就是近似值,多几个节点不影响最终结果):

因此:建堆的时间复杂度为O(N)

5.堆的插入

先插入一个10到数组的尾上,再进行向上调整算法,直到满足堆。

6.堆的删除

删除堆是删除堆顶的数据,将堆顶的数据根最后一个数据一换,然后删除数组最后一个数据,再进行向下调整算法。

7.堆实现

heap.h文件
#pragma once
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
#include <stdio.h>

typedef int HPDataType;

typedef struct Heap
{
    HPDataType* a;
    int size;
    int capacity;
} HP;

// 堆操作接口
void HeapInit(HP* php);
void HeapDestroy(HP* php);
void HeapPush(HP* php, HPDataType x);
void HeapPop(HP* php);      // 删除堆顶
HPDataType HeapTop(HP* php);
bool HeapEmpty(HP* php);
int HeapSize(HP* php);





heap.c文件

#define _CRT_SECURE_NO_WARNINGS
#include "Heap.h"

// 静态辅助函数(仅本文件可见)
static void Swap(HPDataType* p1, HPDataType* p2) 
{
    HPDataType tmp = *p1;
    *p1 = *p2;
    *p2 = tmp;
}

static void AdjustUp(HPDataType* a, int child) 
{
    int parent = (child - 1) / 2;
    while (child > 0) 
    {  // 小堆逻辑
        if (a[child] < a[parent]) 
        {
            Swap(&a[child], &a[parent]);
            child = parent;
            parent = (child - 1) / 2;
        }
        else 
        {
            break;
        }
    }
}

static void AdjustDown(HPDataType* a, int n, int parent) 
{
    int child = parent * 2 + 1;
    while (child < n) 
    {
        // 选择较小的子节点(小堆)
        if (child + 1 < n && a[child + 1] < a[child]) 
        {
            child++;
        }
        if (a[child] < a[parent]) 
        {
            Swap(&a[child], &a[parent]);
            parent = child;
            child = parent * 2 + 1;
        }
        else 
        {
            break;
        }
    }
}

// 初始化堆
void HeapInit(HP* php) 
{
    assert(php);
    php->a = NULL;
    php->size = php->capacity = 0;
}

// 销毁堆
void HeapDestroy(HP* php) 
{
    assert(php);
    free(php->a);
    php->a = NULL;
    php->size = php->capacity = 0;
}

// 插入元素
void HeapPush(HP* php, HPDataType x) 
{
    assert(php);
    // 扩容检查
    if (php->size == php->capacity) 
    {
        int newCapacity = php->capacity == 0 ? 4 : php->capacity * 2;
        HPDataType* tmp = (HPDataType*)realloc(php->a, newCapacity * sizeof(HPDataType));
        if (tmp == NULL) 
        {
            perror("realloc fail");
            exit(EXIT_FAILURE);  // 内存不足直接退出
        }
        php->a = tmp;
        php->capacity = newCapacity;
    }
    // 插入并调整
    php->a[php->size++] = x;
    AdjustUp(php->a, php->size - 1);
}

// 删除堆顶
void HeapPop(HP* php) 
{
    assert(php && !HeapEmpty(php));
    Swap(&php->a[0], &php->a[--php->size]);
    AdjustDown(php->a, php->size, 0);
}

// 获取堆顶元素
HPDataType HeapTop(HP* php)
{
    assert(php && !HeapEmpty(php));
    return php->a[0];
}

// 判断堆是否为空
bool HeapEmpty(HP* php) 
{
    assert(php);
    return php->size == 0;
}

// 获取堆大小
int HeapSize(HP* php) 
{
    assert(php);
    return php->size;
}



main.c  测试文件
int main()
{
    HP hp;
    HeapInit(&hp);

    int a[] = { 12, 34, 56, 70, 45, 67, 13, 35, 43, 67, 89, 90, 112, 113, 456 };
    for (int i = 0; i < sizeof(a) / sizeof(a[0]); i++)
    {
        HeapPush(&hp, a[i]);
    }

    // 小堆特性会从小到大弹出
    while (!HeapEmpty(&hp))
    {
        printf("%d ", HeapTop(&hp));
        HeapPop(&hp);
    }
    return 0;
}

8.堆的应用

 -堆排序
堆排序即利用堆的思想来进行排序,总共分为两个步骤:
1. 建堆
升序:建大堆
降序:建小堆
2. 利用堆删除思想来进行排序
建堆和堆删除中都用到了向下调整,因此掌握了向下调整,就可以完成堆排序。

9.TopK问题

TOP-K问题:即求数据结合中前K个最大的元素或者最小的元素,一般情况下数据量都比较大。
比如:专业前10名、世界500强、富豪榜、游戏中前100的活跃玩家等。
对于Top-K问题,能想到的最简单直接的方式就是排序,但是:如果数据量非常大,排序就不太可取了(可能数据都不能一下子全部加载到内存中)。最佳的方式就是用堆来解决,基本思路如下:
1. 用数据集合中前K个元素来建堆
前k个最大的元素,则建小堆
前k个最小的元素,则建大堆
2. 用剩余的N-K个元素依次与堆顶元素来比较,不满足则替换堆顶元素将剩余N-K个元素依次与堆顶元素比完之后,堆中剩余的K个元素就是所求的前K个最小或者最大的元素。

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <time.h>
#include <stdbool.h>  

// 定义堆中数据的类型,这里使用 int 类型
typedef int HPDataType;

// 定义堆的结构体
typedef struct Heap
{
    HPDataType* a;  // 指向堆数据的指针
    int size;       // 当前堆中元素的数量
    int capacity;   // 堆的容量
} HP;

// 初始化堆
void HeapInit(HP* php) 
{
    // 断言传入的堆指针不为空
    assert(php);
    // 初始化堆数据指针为空
    php->a = NULL;
    // 初始化堆中元素数量为 0
    php->size = 0;
    // 初始化堆的容量为 0
    php->capacity = 0;
}

// 销毁堆,释放堆所占用的内存
void HeapDestroy(HP* php) 
{
    // 断言传入的堆指针不为空
    assert(php);
    // 释放堆数据所占用的内存
    free(php->a);
    // 将堆数据指针置为空
    php->a = NULL;
    // 将堆的容量和元素数量都置为 0
    php->capacity = php->size = 0;
}

// 交换两个元素的值
void Swap(HPDataType* p1, HPDataType* p2) 
{
    // 临时变量,用于存储其中一个元素的值
    HPDataType tmp = *p1;
    *p1 = *p2;
    *p2 = tmp;
}

// 向上调整堆,保持堆的性质
void AdjustUp(HPDataType* a, int child) 
{
    // 计算父节点的索引
    int parent = (child - 1) / 2;
    // 当子节点的索引大于 0 时,继续调整
    while (child > 0) 
    {
        // 如果子节点的值小于父节点的值
        if (a[child] < a[parent]) 
        {
            // 交换子节点和父节点的值
            Swap(&a[child], &a[parent]);
            // 更新子节点为原来的父节点
            child = parent;
            // 重新计算新的父节点的索引
            parent = (child - 1) / 2;
        }
        else 
        {
            // 如果子节点的值不小于父节点的值,停止调整
            break;
        }
    }
}

// 向下调整堆,保持堆的性质
void AdjustDown(int* a, int n, int parent) 
{
    // 计算左子节点的索引
    int child = parent * 2 + 1;
    // 当子节点的索引小于堆中元素的数量时,继续调整
    while (child < n) 
    {
        // 如果右子节点存在且右子节点的值小于左子节点的值
        if (child + 1 < n && a[child + 1] < a[child]) 
        {
            // 更新子节点为右子节点
            ++child;
        }
        // 如果子节点的值小于父节点的值
        if (a[child] < a[parent]) 
        {
            // 交换父节点和子节点的值
            Swap(&a[parent], &a[child]);
            // 更新父节点为原来的子节点
            parent = child;
            // 重新计算新的子节点的索引
            child = parent * 2 + 1;
        }
        else 
        {
            // 如果子节点的值不小于父节点的值,停止调整
            break;
        }
    }
}

// 向堆中插入一个元素
void HeapPush(HP* php, HPDataType x) 
{
    // 断言传入的堆指针不为空
    assert(php);
    // 如果堆的元素数量等于堆的容量,需要扩容
    if (php->size == php->capacity) 
    {
        // 计算新的容量
        int newCapacity = php->capacity == 0 ? 4 : php->capacity * 2;
        // 重新分配内存
        HPDataType* tmp = (HPDataType*)realloc(php->a, newCapacity * sizeof(HPDataType));
        // 如果内存分配失败
        if (tmp == NULL) 
        {
            // 输出错误信息
            perror("realloc fail");
            return;
        }
        // 更新堆数据指针
        php->a = tmp;
        // 更新堆的容量
        php->capacity = newCapacity;
    }
    // 将新元素插入到堆的末尾
    php->a[php->size++] = x;
    // 向上调整堆
    AdjustUp(php->a, php->size - 1);
}

// 判断堆是否为空
bool HeapEmpty(HP* php) 
{
    // 如果堆中元素数量为 0,则堆为空
    return php->size == 0;
}

// 获取堆中元素的数量
int HeapSize(HP* php) 
{
    return php->size;
}

// 删除堆顶元素
void HeapPop(HP* php) 
{
    // 断言传入的堆指针不为空且堆不为空
    assert(php && !HeapEmpty(php));
    // 交换堆顶元素和堆的最后一个元素
    Swap(&php->a[0], &php->a[php->size - 1]);
    // 堆的元素数量减 1
    php->size--;
    // 向下调整堆
    AdjustDown(php->a, php->size, 0);
}

// 获取堆顶元素
HPDataType HeapTop(HP* php) 
{
    // 断言传入的堆指针不为空且堆不为空
    assert(php && !HeapEmpty(php));
    return php->a[0];
}

// 生成随机数据并保存到文件中
void CreateNate()
{
    // 生成 1000 个随机数
    int n = 1000;
    // 初始化随机数种子
    srand(time(0));
    // 定义要保存数据的文件名
    const char* file = "data.txt";
    // 以写入模式打开文件
    FILE* fin = fopen(file, "w");
    // 如果文件打开失败
    if (fin == NULL) 
    {
        // 输出错误信息
        perror("fopen error");
        return;
    }
    // 循环生成随机数并写入文件
    for (int i = 0; i < n; i++) 
    {
        // 生成 0 到 9999 之间的随机数
        int x = rand() % 10000;
        // 将随机数写入文件
        fprintf(fin, "%d\n", x);
    }
    // 关闭文件
    fclose(fin);
}

// 打印文件中最大的 k 个元素
void PrintTopK(int k) 
{
    // 定义要读取数据的文件名
    const char* file = "data.txt";
    // 以读取模式打开文件
    FILE* fin = fopen(file, "r");
    // 如果文件打开失败
    if (fin == NULL) 
    {
        // 输出错误信息
        perror("fopen error");
        return;
    }

    // 分配内存,用于存储最小堆
    int* kminheap = (int*)malloc(sizeof(int) * k);
    // 如果内存分配失败
    if (kminheap == NULL)
    {
        // 输出错误信息
        perror("malloc fail");
        return;
    }

    // 从文件中读取前 k 个元素到最小堆中
    for (int i = 0; i < k; i++) 
    {
        fscanf(fin, "%d", &kminheap[i]);
    }

    // 对最小堆进行建堆操作
    for (int i = (k - 1 - 1) / 2; i >= 0; i--)
    {
        AdjustDown(kminheap, k, i);
    }

    // 用于存储从文件中读取的元素
    int val = 0;
    // 从文件中继续读取元素
    while (fscanf(fin, "%d", &val) != EOF) 
    {
        // 如果读取的元素大于最小堆的堆顶元素
        if (val > kminheap[0]) 
        {
            // 替换堆顶元素
            kminheap[0] = val;
            // 向下调整堆
            AdjustDown(kminheap, k, 0);
        }
    }

    // 打印最小堆中的元素
    for (int i = 0; i < k; i++) 
    {
        printf("%d ", kminheap[i]);
    }
    printf("\n");

    // 释放最小堆所占用的内存
    free(kminheap);
    // 关闭文件
    fclose(fin);
}

int main() 
{
    // 生成随机数据并保存到文件中
    CreateNate();
    // 打印文件中最大的 3 个元素
    PrintTopK(3);
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2374965.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

DedeCMS-Develop-5.8.1.13-referer命令注入研究分析 CVE-2024-0002

本次文章给大家带来代码审计漏洞挖掘的思路&#xff0c;从已知可控变量出发或从函数功能可能照成的隐患出发&#xff0c;追踪参数调用及过滤。最终完成代码的隐患漏洞利用过程。 代码审计挖掘思路 首先flink.php文件的代码执行逻辑&#xff0c;可以使用php的调试功能辅助审计 …

运用数组和矩阵对数据进行存取和运算——NumPy模块 之五

目录 NumPy模块介绍 3.5.1 NumPy 操纵数组元素的逻辑 3.5.2 添加数组元素操作 1. append() 函数 2. insert() 函数 3.5.3 删除数组元素的操作 delete() 函数 3.5.4 数组元素缺失情况的处理 isnan() 函数 3.5.5 处理数组中元素重复情况 unique() 函数 3.5.6 拼接数组操作 1. con…

Nginx的增强与可视化!OpenResty Manager - 现代化UI+高性能反向代理+安全防护

以下是对OpenResty Manager的简要介绍&#xff1a; OpenResty Manager &#xff08;Nginx 增强版&#xff09;&#xff0c;是一款容易使用、功能强大且美观的反向代理工具 &#xff0c;可以作为OpenResty Edge 的开源替代品基于 OpenResty 开发&#xff0c;支持并继承 OpenRes…

Linux:43线程封装与互斥lesson31

mmap文件映射视屏&#xff1a;待看... 目录 线程栈 代码证明&#xff1a;一个线程的数据&#xff0c;其他线程也可以访问 线程封装 简单封装,2.thread Thread.hpp Main.cc Makefile 结果&#xff1a; ​编辑 问题1&#xff1a; 问题2&#xff1a; lamba表达式 模版封…

“工作区”升级为“磁盘”、数据集统计概览优化|ModelWhale 版本更新

本次更新围绕用户在实际项目中对平台的理解和管理体验进行了多项优化。 “工作区”升级为“磁盘”、及其管理优化 平台“工作区”概念正式更名为“磁盘”&#xff0c;突出其存储功能。原有以目录代称的存储区域划分同步更名&#xff0c;其中“work目录”更改为“个人磁盘”&am…

【Mysql基础】一、基础入门和常见SQL语句

&#x1f4da;博客主页&#xff1a;代码探秘者-CSDN博客 &#x1f308;&#xff1a;最难不过坚持 ✨专栏 &#x1f308;语言篇C语言\ CJavase基础&#x1f308;数据结构专栏数据结构&#x1f308;算法专栏必备算法&#x1f308;数据库专栏MysqlRedis&#x1f308;必备篇 其他…

AWS之存储服务

目录 一、传统存储术语 二、传统存储与云存储的关系 三、云存储之AWS 使用场景 文件存储 数据块存储 对象存储 EBS、EFS、S3对比 EBS块存储 S3对象存储 S3 使用案例 S3 存储类 EFS文件存储 一、传统存储术语 分类 接口/技术类型 应用场景特点 关系及区别 机械硬…

Jmeter中的Json提取器如何使用?

在JMeter中使用JSON提取器可以方便地从JSON格式的响应数据中提取特定字段的值。以下是详细步骤和示例&#xff1a; 1. 添加JSON提取器 右击目标HTTP请求 -> 选择 添加 -> 后置处理器 -> JSON提取器。 2. 配置JSON提取器参数 变量名称&#xff08;Names of created…

从零理解 C++ 中的原子布尔变量:`std::atomic<bool>` 入门指南

文章目录 引言&#xff1a;为什么需要原子变量&#xff1f;一、什么是 std::atomic<bool>&#xff1f;二、为什么不用普通 bool&#xff1f;一个反面例子三、std::atomic<bool> 的用法四、std::atomic<bool> 的优势五、完整示例&#xff1a;多线程文件传输六…

六个仓库合并为一个仓库,保留master和develop分支的bat脚本

利用git subtree可以实现多个仓库合并为一个仓库&#xff0c;手动操作起来太麻烦了&#xff0c;今天花了点时间写了一个可执行的脚本&#xff0c;现在操作起来就方便多了。 1、本地新建setup.bat文件 2、用编辑器打开&#xff08;我用的是Notepad&#xff09; 3、把下面代码…

养生:通往健康生活的桥梁

在生活节奏日益加快的今天&#xff0c;养生已成为维持身心健康的必要手段。从日常饮食到运动锻炼&#xff0c;从睡眠质量到心态调节&#xff0c;每一个环节都对我们的生活品质有着重要影响。以下是一些实用的养生建议&#xff0c;帮助你打造健康生活。 饮食养生&#xff1a;均…

【前端基础】9、CSS的动态伪类(hover、visited、hover、active、focus)【注:本文只有几个粗略说明】

一、什么是伪类 选择器的一种&#xff0c;用于选择处于特定状态的元素。 最常见的现象&#xff1a;鼠标放在某些文字上面&#xff0c;文字就会加上颜色。 鼠标没放上去之前&#xff1a; 鼠标放上去之后&#xff1a; 二、动态伪类 图片来源&#xff08;链接文章也有其他伪…

Simufact Welding重塑新能源汽车电池盒焊接工艺

引言 近年来&#xff0c;新能源汽车行业呈爆发式增长&#xff0c;已然成为全球能源转型与汽车产业升级的核心方向。在新能源汽车中&#xff0c;电池系统占据核心地位&#xff0c;作为电池系统重要组成部分的电池盒&#xff0c;也发挥着不可或缺的作用 。目前&#xff0c;电池盒…

WordPress 网站上的 jpg、png 和 WebP 图片插件

核心功能 1. 转换 AVIF 并压缩 AVIF 将您 WordPress 网站上的 jpg、png 和 WebP 图片转换为 AVIF 格式&#xff0c;并根据您设置的压缩级别压缩 AVIF 图片。如果原始图片已经是 WordPress 6.5 以上支持的 AVIF 格式&#xff0c;则原始 AVIF 图片将仅被压缩。 2. 转换 WebP 并…

如何应对网站被爬虫和采集?综合防护策略与实用方案

在互联网时代&#xff0c;网站内容被恶意爬虫或采集工具窃取已成为常见问题。这不仅侵犯原创权益&#xff0c;还可能影响网站性能和SEO排名。以下是结合技术、策略与法律的综合解决方案&#xff0c;帮助网站构建有效防护体系。 一、技术防护&#xff1a;阻断爬虫的“技术防线”…

AI智慧公园管理方案:用科技重塑市民的“夜游体验”

AI智慧公园管理方案&#xff1a;多场景智能巡检与安全防控 一、背景与痛点分析 夏季夜间&#xff0c;公园成为市民休闲娱乐的核心场所&#xff0c;但管理难度随之激增&#xff1a; 宠物管理失控&#xff1a;未牵绳宠物进入园区&#xff0c;随地排泄、惊扰游客&#xff0c;甚…

LVGL- 按钮矩阵控件

1 按钮矩阵控件 lv_btnmatrix 是 LVGL&#xff08;Light and Versatile Graphics Library&#xff09; v8 中提供的一个非常实用的控件&#xff0c;用于创建带有多个按钮的矩阵布局。它常用于实现虚拟键盘、数字键盘、操作面板、选择菜单等场景&#xff0c;特别适用于嵌入式设…

1. 使用 IntelliJ IDEA 创建 React 项目:创建 React 项目界面详解;配置 Yarn 为包管理器

1. 使用 IntelliJ IDEA 创建 React 项目&#xff1a;创建 React 项目界面详解&#xff1b;配置 Yarn 为包管理器 &#x1f9e9; 使用 IntelliJ IDEA 创建 React 项目&#xff08;附 Yarn 配置与 Vite 建议&#xff09;&#x1f4f7; 创建 React 项目界面详解1️⃣ Name&#xf…

【JVM】从零开始深度解析JVM

本篇博客给大家带来的是JVM的知识点, 重点在类加载和垃圾回收机制上. &#x1f40e;文章专栏: JavaEE初阶 &#x1f680;若有问题 评论区见 ❤ 欢迎大家点赞 评论 收藏 分享 如果你不知道分享给谁,那就分享给薯条. 你们的支持是我不断创作的动力 . 王子,公主请阅&#x1f680; …

算法训练营第十四天|110. 平衡二叉树、257. 二叉树的所有路径、404. 左叶子之和、222.完全二叉树的节点个数

110.平衡二叉树 题目 思路与解法 # Definition for a binary tree node. # class TreeNode: # def __init__(self, val0, leftNone, rightNone): # self.val val # self.left left # self.right right class Solution:def isBalanced(self, r…