当前位置: 首页 > article >正文

【数据结构】队列的完整实现

队列的完整实现

  • 队列的完整实现
  • github地址
  • 前言
  • 1. 队列的概念及其结构
    • 1.1 概念
    • 1.2 组织结构
  • 2. 队列的实现
    • 接口一览
    • 结构定义与架构
    • 初始化和销毁
    • 入队和出队
    • 取队头队尾数据
    • 获取size和判空
  • 完整代码与功能测试
  • 结语

队列的完整实现

github地址

有梦想的电信狗

前言

​ 队列(Queue)作为一种基础且重要的数据结构,在计算机科学中扮演着关键角色。无论是操作系统的任务调度、网络数据包的管理,还是算法中的广度优先搜索(BFS),队列的“先进先出”(FIFO)特性都使其成为不可或缺的工具。理解队列的实现原理,不仅能帮助开发者更高效地处理数据,还能为后续学习复杂的数据结构打下坚实基础。

​ 本文将以 链式结构 为核心,详细介绍队列的完整实现。从结构设计、接口定义到功能测试,一步步剖析如何用C语言实现一个高效、健壮的队列。文章重点讲解入队(push)、出队(pop)、获取队头/队尾元素等核心操作,并通过清晰的代码示例和测试案例,帮助读者深入理解队列的内部机制。此外,所有代码已在GitHub开源,方便读者参考和扩展。


1. 队列的概念及其结构

1.1 概念

队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out) 的特性

  • 入队列:进行插入操作的一端称为队尾,入队常被称为push
  • 出队列:进行删除操作的一端称为队头,出队常被称为pop
  • 如下图所示
    在这里插入图片描述

1.2 组织结构

  • 队列可以使用数组链表的结构实现,使用链表的结构实现更优一些。

  • 因为如果使用数组的结构,出队列时,在数组头上出数据,效率会比较低

  • 而对于链表实现的队列来说,入队对应尾插操作,出队对应头删操作。在链表中,头删和尾插操作只需要O(1)时间复杂度,因此队列更适合使用链表来实现,本文我们采用单链表来实现。

在这里插入图片描述


2. 队列的实现

接口一览

//初始化 与 销毁队列
void QueueInit(Queue* pQueue);
void QueueDestroy(Queue* pQueue);// 队尾入队列    队头出队列
void QueuePush(Queue* pQueue, QDataType data);
void QueuePop(Queue* pQueue);// 获取队列头部元素   /获取队列尾部元素
QDataType QueueFront(Queue* pQueue);
QDataType QueueBack(Queue* pQueue);//获取队列中有效元素个数	检测队列是否为空,如果为空返回非零结果,如果非空返回0
int QueueSize(Queue* pQueue);
bool QueueEmpty(Queue* pQueue);

结构定义与架构

结构

//队列,先进先出,数组的话在头部出数据不方便,因此用链表来实现,单链表
typedef int QDataType;typedef struct QNode {		//链式队列,用单链表实现struct QNode* next;QDataType data;
}QNode;//队列中 用两个指针来指示 队头和队尾,方便入队和出队
typedef struct Queue {QNode* head;QNode* tail;int size;
}Queue;
  • 使用typedef int QDataType方便队列中存放不同的数据类型
  • QNode表示我们链表中一个个的结点,内部包含next指针和数据data
  • 使用struct Queue结构来表示整个队列,其中:
    • 规定两个QNode*的指针,分别保存链表第一个结点和尾结点的地址(分别指向第一个结点和最后一个结点)
    • 定义int size来保存队列中的有效元素个数。

架构图如下
在这里插入图片描述

初始化和销毁

初始化

//初始化 与 销毁队列
void QueueInit(Queue* pQueue) {assert(pQueue);pQueue->head = pQueue->tail = NULL;pQueue->size = 0;
}
  • 通过Queue结构体的指针pQueue,来访问结构体中的成员headtail,通过headtail指针和链表的特性,可以访问到链表中的每个结点。headtail指针主要是为了方便访问队头结点和队尾结点。
  • assert(pQueue)保证Queue结构存在
  • 初始化队列
    • 链表中无节点时,headtail指针都置为NULL
    • 初始化size0

销毁

//销毁
void QueueDestroy(Queue* pQueue) {assert(pQueue);// 空链表也可以销毁,因此无需断言链表非空QNode* cur = pQueue->head;while (cur != NULL) {QNode* next = cur->next;free(cur);cur = next;}pQueue->head = pQueue->tail = NULL;pQueue->size = 0;
}
  • assert(pQueue)保证Queue结构存在
  • QNode* cur = pQueue->headcur保存当前头结点的地址
    • while循环依次释放每一个结点
    • 保存cur的下一个节点cur->next
    • free(cur)释放当前结点,cur移动指向下一个节点,直到NULL时结束
  • pQueue->head = pQueue->tail = NULL:将headtail指针各自置NULL
  • pQueue->size = 0最后将size置0

入队和出队

入队

// 队尾入队列    队头出队列
void QueuePush(Queue* pQueue, QDataType data) {assert(pQueue);// 开辟新结点,并将数据置于新结点中QNode* newNode = (QNode*)malloc(sizeof(QNode));if (newNode == NULL) {perror("malloc failed\n");return;}newNode->data = data;newNode->next = NULL;// 初始化后,head 和 tail 都为NULLif (pQueue->head == NULL) {assert(pQueue->tail == NULL);	// head为NULL时,tail必须也为NULLpQueue->head = pQueue->tail = newNode;}else {pQueue->tail->next = newNode;pQueue->tail = newNode;}pQueue->size++;
}
  • assert(pQueue)保证Queue结构存在
  • QNode* newNode = (QNode*)malloc(sizeof(QNode)); if (newNode == NULL) { perror("malloc failed\n"); return; }开辟一个新结点,并进行初始化
  • 初始化QNode后,push 一个结点本质是单链表的尾插,有两种情况:
    • 队列为空(队列中无节点)时:新开辟的QNode应当成为链表中的第一个节点,pQueue->head = pQueue->tail = newNode操作调整首尾指针即可。
    • 队列中已有其他结点时:此时是单链表的尾插
      • pQueue->tail->next = newNode:新结点链入原链表
      • pQueue->tail = newNode:更改尾指针指向
  • push过后,pQueue->size++,队列的size应当++

出队

v1版本仅实现

void QueuePop(Queue* pQueue) {assert(pQueue);assert(pQueue->head != NULL);//if(pQueue->head->next == NULL){}	//考虑只剩一个结点的情况if (pQueue->head == pQueue->tail) {	free(pQueue->head);pQueue->head = pQueue->tail = NULL;}else {QNode* cur = pQueue->head;pQueue->head = pQueue->head->next;free(cur);cur = NULL;}pQueue->size--;
}
  • assert(pQueue)断言队列存在assert(pQueue->head != NULL)确保pop时队列内有元素
  • pop出队时,销毁第一个结点,确保队列存在且有元素后,此处存在两种情况
    • 当前仅剩一个结点时pQueue->head == pQueue->tail,直接free当前头结点,将headtail指针置NULL即可
    • 当前存在多个节点时(else)
      • QNode* cur = pQueue->head:记录下当前的头结点
      • pQueue->head = pQueue->head->next:头指针向后移动
      • free(cur)cur = NULL释放之前的头结点的空间,并将curNULL
  • popsize应当--

v2版本优化

  • 可以看到,上述的代码中存在多次free,且都是对要被删除的结点进行free,那么是否可以优化为一次free
void QueuePop(Queue* pQueue) {assert(pQueue);assert(pQueue->head != NULL);//优化版本QNode* cur = pQueue->head;if (pQueue->head == pQueue->tail)pQueue->head = pQueue->tail = NULL;elsepQueue->head = pQueue->head->next;free(cur);cur = NULL;pQueue->size--;
}
  • assert(pQueue)断言队列存在assert(pQueue->head != NULL)确保pop时队列内有元素
  • QNode* cur = pQueue->head:不管队列中剩余几个结点,最终都要free头结点,那么cur直接保存头结点的地址,方便进行操作
  • pQueue->head == pQueue->tail仅剩一个结点时:仅需对headtail指针做修改。有多个节点时,pQueue->head = pQueue->head->nexthead指针向后移动。
  • 最终cur内保存了要被删除的结点的地址,直接free(cur)并置NULL
  • popsize应当--

取队头队尾数据

获取队头数据

// 获取队列头部元素   获取队列尾部元素
QDataType QueueFront(Queue* pQueue) {assert(pQueue);//确保队列非空assert(!QueueEmpty(pQueue));return pQueue->head->data;
}
  • assert(pQueue)确保队列存在,assert(!QueueEmpty(pQueue))确保队列非空,非空队列内才有数据
  • 头部数据return pQueue->head->data,通过头指针head访问队列内第一个结点的数据

获取队尾数据

//获取队列尾部元素
QDataType QueueBack(Queue* pQueue) {assert(pQueue);//确保队列非空assert(!QueueEmpty(pQueue));return pQueue->tail->data;
}
  • assert(pQueue)确保队列存在,assert(!QueueEmpty(pQueue))确保队列非空,非空队列内才有数据
  • 尾部数据return pQueue->tail->data,通过尾指针tail访问队列内最后一个结点的数据

获取size和判空

获取size

int QueueSize(Queue* pQueue) {assert(pQueue);return pQueue->size;
}
  • assert(pQueue):断言指针非空,确保Queue结构体存在
  • 直接返回size即可得到元素个数
    • 这里就体现出我们在Queue结构中添加一个size成员的好处,只需在每次Push/Pop后对size进行加减,即可方便的得到队列的size
    • 如果Queue结构内不维护一个size变量的话,由于我们的队列基于单链表实现的,每次获取队列的大小时都只能遍历链表来得到size,遍历的时间复杂度较高。

判空

bool QueueEmpty(Queue* pQueue) {assert(pQueue);//return (pQueue->head == NULL && pQueue->tail == NULL);return pQueue->size == 0;	// size为0时为空
}
  • assert(pQueue):断言指针非空,确保Queue结构体存在
  • pQueue->size == 0pQueue->head == NULL && pQueue->tail == NULL,两个条件均可以标识队列为空

完整代码与功能测试

完整代码如下

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>//队列,先进先出,数组的话在头部出数据不方便,因此用链表来实现,单链表
typedef int QDataType;typedef struct QNode {		//链式队列,用单链表实现struct QNode* next;QDataType data;
}QNode;//队列中 用两个指针来指示 队头和队尾,方便入队和出队
typedef struct Queue {QNode* head;QNode* tail;int size;
}Queue;//初始化 与 销毁队列
void QueueInit(Queue* pQueue);
void QueueDestroy(Queue* pQueue);// 队尾入队列    队头出队列
void QueuePush(Queue* pQueue, QDataType data);
void QueuePop(Queue* pQueue);// 获取队列头部元素   /获取队列尾部元素
QDataType QueueFront(Queue* pQueue);
QDataType QueueBack(Queue* pQueue);//获取队列中有效元素个数	检测队列是否为空,如果为空返回非零结果,如果非空返回0
int QueueSize(Queue* pQueue);
bool QueueEmpty(Queue* pQueue);// #include "Queue.h" 多文件编译时,需正确包含头文件//初始化 与 销毁队列
void QueueInit(Queue* pQueue) {assert(pQueue);pQueue->head = pQueue->tail = NULL;pQueue->size = 0;
}
//销毁
void QueueDestroy(Queue* pQueue) {assert(pQueue);QNode* cur = pQueue->head;while (cur != NULL) {QNode* next = cur->next;free(cur);cur = next;}pQueue->head = pQueue->tail = NULL;pQueue->size = 0;
}// 队尾入队列    队头出队列
void QueuePush(Queue* pQueue, QDataType data) {assert(pQueue);QNode* newNode = (QNode*)malloc(sizeof(QNode));if (newNode == NULL) {perror("malloc failed\n");return;}newNode->data = data;newNode->next = NULL;// 初始化后,head 和 tail 都为NULLif (pQueue->head == NULL) {assert(pQueue->tail == NULL);	// head为NULL时,tail必须也为NULLpQueue->head = pQueue->tail = newNode;}else {pQueue->tail->next = newNode;pQueue->tail = newNode;}pQueue->size++;
}
//队列的头删法
void QueuePop(Queue* pQueue) {assert(pQueue);assert(pQueue->head != NULL);if(pQueue->head->next == NULL){}	//考虑只剩一个结点的情况//if (pQueue->head == pQueue->tail) {	//	free(pQueue->head);//	pQueue->head = pQueue->tail = NULL;//}//else {//	QNode* cur = pQueue->head;//	pQueue->head = pQueue->head->next;//	free(cur);//	cur = NULL;//}//pQueue->size--;//优化版本QNode* cur = pQueue->head;if (pQueue->head == pQueue->tail)pQueue->head = pQueue->tail = NULL;elsepQueue->head = pQueue->head->next;free(cur);cur = NULL;pQueue->size--;
}// 获取队列头部元素   获取队列尾部元素
QDataType QueueFront(Queue* pQueue) {assert(pQueue);//确保队列非空assert(!QueueEmpty(pQueue));return pQueue->head->data;
}
//获取队列尾部元素
QDataType QueueBack(Queue* pQueue) {assert(pQueue);//确保队列非空assert(!QueueEmpty(pQueue));return pQueue->tail->data;
}//获取队列中有效元素个数	检测队列是否为空,如果为空返回非零结果,如果非空返回0
// 双向链表中,不能用 哨兵位的数据  来存储 链表的长度
// 之前的实现中,结点内存放的数据是int,导致哨兵位内的数据位类型也是int,
int QueueSize(Queue* pQueue) {assert(pQueue);return pQueue->size;
}
bool QueueEmpty(Queue* pQueue) {assert(pQueue);//return (pQueue->head == NULL && pQueue->tail == NULL);return pQueue->size == 0;	// size为0时为空
}

功能测试

// 需正确包含头文件
#include "Queue.h"void TestQueue() {Queue queue;QueueInit(&queue);QueuePush(&queue, 1);QueuePush(&queue, 2);QueuePush(&queue, 3);QueuePush(&queue, 4);QueuePush(&queue, 6);// 遍历的代码/*while (!QueueEmpty(&queue)) {printf("%d ", QueueFront(&queue));QueuePop(&queue);}*/printf("队尾:%d  有效元素个数:%d\n", QueueBack(&queue), QueueSize(&queue));printf("队头:%d  有效元素个数:%d\n", QueueFront(&queue), QueueSize(&queue));QueuePop(&queue);printf("队尾:%d  有效元素个数:%d\n", QueueBack(&queue), QueueSize(&queue));printf("队头:%d  有效元素个数:%d\n", QueueFront(&queue), QueueSize(&queue));QueuePop(&queue);printf("队尾:%d  有效元素个数:%d\n", QueueBack(&queue), QueueSize(&queue));printf("队头:%d  有效元素个数:%d\n", QueueFront(&queue), QueueSize(&queue));QueuePop(&queue);QueuePop(&queue);printf("队列有效元素个数:%d\n", QueueSize(&queue));while (!QueueEmpty(&queue)) {printf("%d ", QueueFront(&queue));QueuePop(&queue);}QueueDestroy(&queue);
}//函数调用的栈帧  和  数据结构的栈
// 函数调用的栈帧  是操作系统层面对内存区域的划分
// 和  数据结构的栈int main() {TestQueue();return 0;
}

在这里插入图片描述


结语

通过本文的学习,我们完成了队列的完整实现:从结构体设计到核心接口的实现,再到功能验证。关键点包括:

  1. 链式结构的优势:使用单链表实现队列,确保入队(尾插)和出队(头删)操作的时间复杂度均为 O(1)
  2. 双指针的妙用:通过 headtail 指针分别标记队头和队尾,避免了遍历链表的性能损耗。
  3. 健壮性保障:通过断言(assert)确保操作合法性,并结合 size 字段快速判断队列状态。

希望本文能帮助你彻底掌握队列的实现原理,并激发对数据结构更深层次的探索。


以上就是本文的所有内容了,如果觉得文章对你有帮助,欢迎 点赞⭐收藏 支持!如有疑问或建议,请在评论区留言交流,我们一起进步

分享到此结束啦
一键三连,好运连连!

你的每一次互动,都是对作者最大的鼓励!


征程尚未结束,让我们在广阔的世界里继续前行! 🚀

相关文章:

【数据结构】队列的完整实现

队列的完整实现 队列的完整实现github地址前言1. 队列的概念及其结构1.1 概念1.2 组织结构 2. 队列的实现接口一览结构定义与架构初始化和销毁入队和出队取队头队尾数据获取size和判空 完整代码与功能测试结语 队列的完整实现 github地址 有梦想的电信狗 前言 ​ 队列&…...

2025 全球优质 AI 产品深度测评:从通用工具到垂直领域的技术突围 —— 轻量聚合工具篇

在 AI 技术爆发式增长的 2025 年&#xff0c;全球范围内涌现出大量兼具技术创新与场景价值的优质产品。本文从通用对话、多模态生成、开发者工具、企业级方案及垂直领域深耕五个维度&#xff0c;深度解析 18 款国内外标杆产品&#xff0c;附独家对比数据与选型策略&#xff0c;…...

Python爬虫实战:获取天气网最近一周北京的天气数据,为日常出行做参考

1. 引言 随着互联网技术的发展,气象数据的获取与分析已成为智慧城市建设的重要组成部分。天气网作为权威的气象信息发布平台,其数据具有较高的准确性和实时性。然而,人工获取和分析天气数据效率低下,无法满足用户对精细化、个性化气象服务的需求。本文设计并实现了一套完整…...

根据YOLO数据集标签计算检测框内目标面积占比(YOLO7-10都适用)

程序&#xff1a; 路径改成自己的&#xff0c;阈值可以修改也可以默认 #zhouzhichao #25年5月17日 #计算时频图中信号面积占检测框面积的比值import os import numpy as np import pandas as pd from PIL import Image# Define the path to the directory containing the lab…...

Helm简介、安装、配置、使用!

一、简介 Helm 是 Kubernetes 的包管理器。包管理器类似于我们在 Ubuntu 中使用的apt、Centos中使用的yum 或者Python中的 pip 一样&#xff0c;能快速查找、下载和安装软件包。Helm 由客户端组件 helm 和服务端组件 Tiller 组成, 能够将一组K8S资源打包统一管理, 是查找、共享…...

LLM笔记(九)KV缓存(2)

文章目录 1. 背景与动机2. 不使用 KV Cache 的情形2.1 矩阵形式展开2.2 计算复杂度 3. 使用 KV Cache 的优化3.1 核心思想3.2 矩阵形式展开3.3 计算复杂度对比 4. 总结5. GPT-2 中 KV 缓存的实现分析5.1 缓存的数据结构与类型5.2 在注意力机制 (GPT2Attention) 中使用缓存5.3 缓…...

开发 前端搭建npm v11.4.0 is known not to run on Node.js v14.18.1.

错误nodejs 和npm 版本不一致 ERROR: npm v11.4.0 is known not to run on Node.js v14.18.1. This version of npm supports the following node versions: ^20.17.0 || >22.9.0. You can find the latest version at https://nodejs.org/. ERROR: D:\softTool\node-v14…...

LVS 负载均衡集群应用实战

前提:三台虚拟机,有nginx,要做负载 1. LVS-server 安装lvs管理软件 [root@lvs-server ~]# yum -y install ipvsadm 程序包:ipvsadm(LVS管理工具) 主程序:/usr/sbin/ipvsadm 规则保存工具:/usr/sbin/ipvsadm-save > /path/to/file 配置文件:/etc/sysconfig/ipvsad…...

MySQL——基本查询内置函数

目录 CRUD Create Retrieve where order by limit Update Delete 去重操作 聚合函数 聚合统计 内置函数 日期函数 字符函数 数学函数 其它函数 实战OJ 批量插入数据 找出所有员工当前薪水salary情况 查找最晚入职员工的所有信息 查找入职员工时间升序排…...

Day34打卡 @浙大疏锦行

知识点回归&#xff1a; CPU性能的查看&#xff1a;看架构代际、核心数、线程数GPU性能的查看&#xff1a;看显存、看级别、看架构代际GPU训练的方法&#xff1a;数据和模型移动到GPU device上类的call方法&#xff1a;为什么定义前向传播时可以直接写作self.fc1(x) 作业 计算资…...

【Jitsi Meet】(腾讯会议的平替)Docker安装Jitsi Meet指南-使用内网IP访问

Docker安装Jitsi Meet指南-使用内网IP访问 下载官方代码配置环境变量复制示例环境文件并修改配置&#xff1a;编辑 .env 文件&#xff1a; 修改 docker-compose.yml 文件生成自签名证书启动服务最终验证 腾讯会议的平替。我们是每天开早晚会的&#xff0c;都是使用腾讯会议。腾…...

AdGuard解锁高级版(Nightly)_v4.10.36 安卓去除手机APP广告

AdGuard解锁高级版(Nightly)_v4.10.36 安卓去除手机APP广告 AdGuard Nightly是AdGuard团队为及时更新软件而推出的最新测试版本&#xff0c;适合追求最新功能和愿意尝试新版本的用户。但使用时需注意其潜在的不稳定性和风险。…...

C++修炼:红黑树的模拟实现

Hello大家好&#xff01;很高兴我们又见面啦&#xff01;给生活添点passion&#xff0c;开始今天的编程之路&#xff01; 我的博客&#xff1a;<但凡. 我的专栏&#xff1a;《编程之路》、《数据结构与算法之美》、《题海拾贝》、《C修炼之路》 欢迎点赞&#xff0c;关注&am…...

基于Python+YOLO模型的手势识别系统

本项目是一个基于Python、YOLO模型、PyQt5的实时手势识别系统&#xff0c;通过摄像头或导入图片、视频&#xff0c;能够实时识别并分类不同的手势动作。系统采用训练好的深度学习模型进行手势检测和识别&#xff0c;可应用于人机交互、智能控制等多种场景。 1、系统主要功能包…...

自制操作系统day10叠加处理

day10叠加处理 叠加处理&#xff08;harib07b&#xff09; 现在是鼠标的叠加处理&#xff0c;以后还有窗口的叠加处理 涉及图层 最上面小图层是鼠标指针&#xff0c;最下面的一张图层用来存放桌面壁纸。移动图层的方法实现鼠标指针的移动以及窗口的移动。 struct SHEET { u…...

docker初学

加载镜像&#xff1a;docker load -i ubuntu.tar 导出镜像&#xff1a;docker save -o ubuntu1.tar ubuntu 运行&#xff1a; docker run -it --name mu ubuntu /bin/bash ocker run -dit --name mmus docker.1ms.run/library/ubuntu /bin/bash 进入容器&#xff1a;docke…...

## Docker 中 Elasticsearch 启动失败:日志文件权限问题排查与解决

好的&#xff0c;这是一份关于你遇到的 Docker Elasticsearch 启动报错问题的笔记&#xff0c;包含问题描述、我的分析判断以及最终的解决方案&#xff0c;适合用于整理成文章。 Docker 中 Elasticsearch 启动失败&#xff1a;日志文件权限问题排查与解决 在使用 Docker部署 E…...

鸿蒙Flutter实战:23-混合开发详解-3-源码模式引入

引言 在前面的文章混合开发详解-2-Har包模式引入中&#xff0c;我们介绍了如何将 Flutter 模块打包成 Har 包&#xff0c;并引入到原生鸿蒙工程中。本文中&#xff0c;我们将介绍如何通过源码依赖的方式&#xff0c;将 Flutter 模块引入到原生鸿蒙工程中。 创建工作 创建一个…...

leetcode:2469. 温度转换(python3解法,数学相关算法题)

难度&#xff1a;简单 给你一个四舍五入到两位小数的非负浮点数 celsius 来表示温度&#xff0c;以 摄氏度&#xff08;Celsius&#xff09;为单位。 你需要将摄氏度转换为 开氏度&#xff08;Kelvin&#xff09;和 华氏度&#xff08;Fahrenheit&#xff09;&#xff0c;并以数…...

【软件安装】Windows操作系统中安装mongodb数据库和mongo-shell工具

这篇文章&#xff0c;主要介绍Windows操作系统中如何安装mongodb数据库和mongo-shell工具。 目录 一、安装mongodb数据库 1.1、下载mongodb安装包 1.2、添加配置文件 1.3、编写启动脚本&#xff08;可选&#xff09; 1.4、启动服务 二、安装mongo-shell工具 2.1、下载mo…...

跨域问题及其CORS解决方案:gin框架中配置跨域

一、同源策略 浏览器的同源策略&#xff08;Same-Origin Policy&#xff09;要求&#xff1a;只有协议、域名和端口都相同的请求才被视为同源&#xff0c;才允许正常访问。 两个URL在以下三个方面完全相同时称为"同源"&#xff1a; 协议相同&#xff08;如都是http或…...

记共享元素动画导致的内存泄露

最近在给项目的预览图片页增加共享元素动画的时候&#xff0c;发现了LeakCanary一直报内存泄露。 LeakCanary日志信息 ┬─── │ GC Root: Thread object │ ├─ java.lang.Thread instance │ Leaking: NO (the main thread always runs) │ Thread name: main │ …...

Flyweight(享元)设计模式 软考 享元 和 代理属于结构型设计模式

1.目的&#xff1a;运用共享技术有效地支持大量细粒度的对象 Flyweight&#xff08;享元&#xff09;设计模式 是一种结构型设计模式&#xff0c;它的核心目的是通过共享对象来减少内存消耗&#xff0c;特别是在需要大量相似对象的场景中。Flyweight 模式通过将对象的共享细节与…...

Win/Linux安装flash attention2

1.Win 安装Flash_attn &#xff08;1&#xff09;第一步&#xff1a;下载flash_attn-xxx.whl 文件 在 1&#xff09;地址1&#xff1a;HuggingFace 官网 Flash-attn页面 2&#xff09;地址2&#xff1a;Github 地址 下载对应cuda、torch、python版本的whl文件&#xff1b; …...

【原创】ubuntu22.04下载编译AOSP 15

安装依赖的库&#xff0c;顺便把vim 也安装一下 sudo apt-get install vim sudo apt-get install git gnupg flex bison build-essential zip curl zlib1g-dev libc6-dev-i386 x11proto-core-dev libx11-dev lib32z1-dev libgl1-mesa-dev libxml2-utils xsltproc unzip font…...

服务器网络配置 netplan一个网口配置两个ip(双ip、辅助ip、别名IP别名)

文章目录 问答 问 # This is the network config written by subiquity network:ethernets:enp125s0f0:dhcp4: noaddresses: [192.168.90.180/24]gateway4: 192.168.90.1nameservers:addresses:- 172.0.0.207- 172.0.0.208enp125s0f1:dhcp4: trueenp125s0f2:dhcp4: trueenp125…...

响应面法(Response Surface Methodology ,RSM)

响应面法是一种结合统计学和数学建模的实验优化技术&#xff0c;通过有限的实验数据&#xff0c;建立输入变量与输出响应之间的数学模型&#xff0c;找到最优操作条件。 1.RSM定义 RSM通过设计实验、拟合数学模型&#xff08;如多项式方程&#xff09;和分析响应曲面&#xff…...

针对面试-java集合篇

1.什么是数组 数组(Array)是一种用连续的内存空间存储相同数据类型数据的线性数据结构。 2.数组下标为什么从0开始 寻址公式是:baseAddressi*dataTyeSize&#xff0c;计算下标的内存地址效率较高 3.查找的时间复杂度 随机(通过下标)查询的时间复杂度是O(1) 查找元素(未知…...

Spring Boot 拦截器:解锁5大实用场景

一、Spring Boot中拦截器是什么 在Spring Boot中&#xff0c;拦截器&#xff08;Interceptor&#xff09;是一种基于AOP&#xff08;面向切面编程&#xff09;思想的组件&#xff0c;用于在请求处理前后插入自定义逻辑&#xff0c;实现权限校验、日志记录、性能监控等非业务功能…...

展锐 Android 15 锁定某个App版本的实现

Android 15 系统锁定Antutu版本的实现方法 在Android系统开发中,有时需要锁定特定应用的版本以确保系统稳定性或测试一致性。本文将介绍如何通过修改Android源码来锁定Antutu跑分软件的版本。 修改概述 这次修改主要涉及以下几个方面: 禁用产品复制文件的检查添加指定版本…...