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

C++手撕STL-其叁

Deque

今天我们进入新的容器:deque,一般叫做双端队列。

比起传统的先入先出的队列queue,deque的出场率显然要低得多,事实上deque比起queue来说最大的特点就是多了一个push_front()和pop_front(),其他并没有太多不同。

我们首先来介绍deque的真实数据结构:

在queue中,我们只能操作队列尾部的元素(添加或者删除),所以队列可以用一个数组来实现,队列也确实是严谨的地址连续的数组。而双端队列则不然:他的队列头部也可以操作元素,这就带来一个问题:我们怎么给地址连续的数据结构的首部添加元素呢?

如图所示,他是通过一个中控的数组来控制多个缓冲区(缓冲区就是我们添加的元素),然后中控数组和各个缓冲区的地址是连续的,我们用迭代器start()和end()来实现对deque的访问。

template<class T, class Alloc=alloc, size_t Bufsize = 0>
class deque {
public:typedef T value_type;typedef value_type pointer*;typedef size_t size_type;// ...
public:typedef _deque_iterator<T, T &, T *, BufSiz> iterator;
protected:typedef pointer *map_pointer;
protected:iterator start;iterator finish;map_pointer map;//指向mapsize_type map_size;//map内可容纳多少指针
}

这是deque的大体代码,其中的map_pointer类型就是我们的中控数组类型,size_type类型的map_size则是表明我们的中控数组具体可以容纳多少指针。deque除了维护⼀个map指针以外,还维护了startfinish迭代器分别指向第⼀缓冲区的第⼀个元素,和最后⼀个缓冲区的最后⼀个元素的下⼀个元素,同时它还必须记住当前map的大小。

然后我们首先来看看deque的迭代器具体是怎么工作的:

template<class T, class Ref, class Ptr, size_t BufSiz>
struct _deque_iterator {typedef _deque_iterator<T, T &, T *, BufSiz> iterator;typedef _deque_iterator<T, cosnt T &, const T *, BufSiz> const_iterator;static size_t buffer_size() { return _deque_buf_size(BufSiz, sizeof(T)); };typedef randem_access_iterator_tag iterator_category;typedef T value_type;typedef Ptr pointer;typedef Ref reference;typedef size_t size_type;typedef ptrdiff_t difference_type;typedef T **map_pointer;typedef _deque_iterator self;T *cur;T *first;T *last;map_pointer node;// ...//这是⼀个设置缓存区⼤⼩的函数inline size_t _deque_buf_size(size_t n, size_t sz) {return n != 0 ? n :(sz < 512 ? size_t(512 / sz) : size_t(1));}
}

可以看到首先是常量/非常量的迭代器:常量迭代器满足查的需求而非常量满足增删改的需求。

然后我们是一个返回缓冲区大小的函数,一个是否允许随机访问的变量(之前的vector中出现过),数据类型,指针,引用,数据大小,指针差异(之前vector都有),然后是一个T**的数据类型(T**是什么呢其实就是一个指向T类型指针的指针(从右往左看))变量map_pointer,这里他指向的自然就是我们的中控数组(确切地说,数组指针)。

下面是一个用inline修饰的函数:设置缓冲区大小的函数,其中的内容含义是:参数为数据个数n和元素大小sz,如果n不等于0则直接返回n,否则我们判断单个元素的大小是否超过512,超过的话就返回1(占据一个缓冲区),否则我们就用512来除以元素大小来表示可以存储的元素个数。可能看起来有点晕,其实核心思路就是如果一个元素过大我们一个缓冲区就存一个元素,否则我们一个缓冲区可以多存几个元素,我们用这个准则来设置缓冲区大小。

然后是我们迭代器的一系列方法:

//迭代器的关键⾏为,其中要注意的是⼀旦遇到缓冲区边缘,可能需要跳⼀个缓存区
void set_node(map_pointer new_node) {node = new_node;first = *new_node;last = first + difference_type(buffer_size());
}
//接下来᯿载运算⼦是_deque_iterator<>成功运作的关键
reference operator*() const { return *cur; }
pointer operator->() const { return &(operator*()); }
difference_type operator— (const self &x) const {return difference_type (buffer_szie()) * (node-x.node-1)+(cur-first)+(x.last-x.cur);
}
self &operator++() {++cur;if (cur == last) {set_node(node + 1);cur = first;}return *this;
}
self operator++(int) {self temp = *this;++*this;return temp;
}
self &operator--() {if (cur == first) {set_node(node - 1);cur = last;}--cur;return *this;
}
self operator-(int) {self temp = *this;--*this;return temp;
}
//以下实现随机存取,迭代器可以直接跳跃n个距离
self &operator+=(difference_type n) {difference_type offest = n + (cur - first);if (offest > 0 && offest < difference_type(buffer_size()))cur += n;else {offest > 0 ? offest / fifference_type(buffer_size()) : -difference_type((-
offest - 1) / buffer_size()) - 1;set_node(node + node_offest);cur = first + (offest - node_offest * difference_type(buffer_size()));}return *this;
}
self operator+(differnece_type n) {self tmp = *this;return tmp += n;
}
self operator-=() { return *this += -n; }
self operator-(difference_type n) {self temp = *this;return *this -= n;
}
rference operator[](difference_type n) {return *(*this + n);
}
bool operator==(const self &x) const { return cur == x.cur; }
bool operator!=(const self &x) const { return !(*this == x); }
bool operatoe<(const self &x) const {return (node == x.node) ? (cur < x.cur) : (node - x.node);
}

set_node是一个切换缓冲区的函数,我们把node、first、last都切换为新缓冲区的对应元素,然后是解指针和引用的运算符重载,我们重载*和->来返回指针和引用。然后是迭代器的距离计算函数,然后就是迭代器的移动,通过重载++和--实现,这里注意我们似乎有一个返回引用而一个不返回引用,这是为什么呢?那是因为其实我们做了一个前置自增和后置自增,也就是++i和i++的区别:对于前置自增,我们直接在原地修改数据,所以直接返回引用即可;而后置自增我们返回的是复制出来的备份,显然只能返回数据本身。剩下的无非就是一些基本的迭代器中的运算符重载,不再赘述。

回到我们的deque类,我们的deque的空间分配器有两个:
 

typedef simple_alloc <value_type, Alloc> data_allocator;
typedef simple_alloc <pointer, Alloc> map_allocator;

如果你还不知道什么是分配器的话:

对于deque中,需要管理内存的有两部分:中控数组和缓冲区。

deque(int n, const value_type &value) : start(), finish(), map(0), map_size(0) {fill_initialize(n, value);//这个函数就是⽤来构建deque结构,并设⽴初值
}
template<class T, class Alloc, size_t BufSize)
void deque<T, Alloc, BufSize>::fill_initialize(size_type n, const value_type &value) {creat_map_and_node(n);//安排结构map_pointer cur;_STL_TRY {//为每个缓存区赋值for (cur=start.node;cur<finish.node;++cur)uninitalized_ fill(*cur, *cur+buffer_size(), value);//设置最后⼀个节点有⼀点不同uninitalized_fill(finish.first, finish.cur, value);}catch() {// ...}
}
template<class T, class Alloc, size_t Bufsize>
void deque<T, alloc, Bufsize>::creat_map_and_node(size_type num_elements) {//需要节点数=元素个数/每个缓存区的可容纳元素个数+1size_type num_nodes = num_elements / Buf_size() + 1;map_size = max(initial_map_size(), num_nodes + 2);//前后预留2个供扩充//创建⼀个⼤⼩为map_size的mapmap = map_allocator::allocate(map_size);//创建两个指针指向map所拥有的全部节点的最中间区段map_pointer nstart = map + (map_size() - num_nodes) / 2;map_poniter nfinish = nstart + num_nodes - 1;map_pointer cur;_STL_TRY {//为每个节点配置缓存区for (cur=nstart;cur<nfinish;++cur)+cur=allocate_node();}catch() {// ...}//最后为deque内的start和finish设定内容start.set_node(nstart);finish.set_node(nfinish);start.cur = start.first;finish.cur = finish.first + num_elements % buffer_szie();
}

一开始的构造函数不用多说。

写deque命名空间内的初始化函数fill_initialize,准确地说是填充函数,使用了一个STL_TRY和catch,其实就是宏定义下替换的try。

void push_back(const value_type &t) {if (finish.cur != finish.last - 1) {construct(finish.cur, t);++finish.cur;} elsepush_back_aux(t);
}
// 由于尾端只剩⼀个可⽤元素空间(finish.cur=finish.last-1),
// 所以我们必须᯿新配置⼀个缓存区,在设置新元素的内容,然后更改迭代器的状态
tempalate<class T, class Alloc, size_t BufSize>
void deque<T, alloc, BufSize>::push_back_aux(const value_type &t) {value_type t_copy = t;reserve_map_at_back();*(finish.node + 1) = allocate_node();_STL_TRY {construct(finish.cur, t_copy);finish.set_node(finish.node+1);finish.cur=finish.first;}- STL_UNWIND {deallocate_node(*(finish.node + 1));}
}
//push_front也是⼀样的逻辑

最后实现我们的push_back和push_front函数,最大的点就是要关注我们的map(中控数组)是否有扩容的需求,有的话我们要重新开辟一块新的内存空间,然后把我们的中控数组复制过去,然后把各个缓冲区的指针也复制过去,这样我们扩容的开销就会非常之小。

Stack 

讲述完我们的deque之后,我们就来聊聊在deque的基础之上完成的配接器吧:

如果你还不知道什么是配接器的话:

大白话说的话就是:把接口不适配的容器进行接口修改以达到适配的效果。

虽然我觉得应该没有人不认识栈和队列,但还是给大家一个图先:

栈的源码如图:

template<class T, class Sequence=deque<T>>
class stack {
public:typedef typename Sequence::value_type value_type;typedef typename Sequence::size_type size_type;typedef typename Sequence::reference reference;typedef typename Sequence::const_reference const_reference;
protected:Sequence c;  // 底层容器对象
};

 我们在类模板中提供名为Sequense的参数且默认为deque<T>,然后取Sequense中的变量进行类型名重命名。

bool empty() const { return c.empty(); }
size_type size() const { return c.size(); }
reference top() { return c.back(); }
void push(const value_type &x) { c.push_back(x); }
void pop_back() { c.pop_back(); }

一些基本的方法 。

template<class T, class Sequence>
bool operator==(const stack<T,Sequence>& x, const stack<T,Sequence>& y) {return x.c == y.c;
}
template<class T, class Sequence>
bool operator<(const stack<T,Sequence>& x, const stack<T,Sequence>& y) {return x.c < y.c;
}

重载==和<。 

stack<int, vector<int>> custom_stack;  // 使用vector作为底层

这里是显示地声明创建底层实现为vector<int>的适配器stack。 

priority_queue

写完了栈怎么能不写堆呢?

如果有人不知道堆的话:

话虽如此,在C++之中并没有堆的现成数据结构,但是有堆的实现算法,而优先队列本质上其实就是一个堆,但是他还提供了类似于队列的访问方式和数据结构。

template<class T, class Sequence=vector <T>, class Compare=less<typename
Sequence::value_type>>
class priority_queue {
public:typedef typename Sequence::value_type value_type;typedef typename Sequence::size_type size_type;typedef typename Sequence::reference reference;typedef typename Sequence::const_reference const_refernece;
protected:Sequence c;//底层容器Compare comp//容器⽐较⼤⼩标准
public: priority_queue() : c() {}explicit priority_queue(const Compare &x) : c(), comp(x) {}//以下⽤到的make_heap(),push_heap(),pop_heap()都是C++自带的泛型算法//任何⼀个构造函数都可以⽴即在底层产⽣⼀个heaptemplate<class InputIterator>priority_queue(InputIterator first, InputIterator last const Compare &x):c(first, last), comp(x) { make_heap(c.begin(), c.end(), comp); }template<class InputIterator>priority_queue(InputIterator first, InputIterator last const Compare &x):c(first, last) { make_heap(c.begin(), c.end(), comp); }bool empty() const { return c.empty(); }size_type size() const { return c.size(); }const_reference top() const { return c.front(); }void push(const value_type &x) {_STL_TRY {c.push_back(X);push_heap(c.begin(), c.end(), comp);}_STL_UNWIND{c.clear()};}void pop() {_STL_TRY {pop_heap(c.begin(), c.end(), comp);c.pop_back();}_STL_UNWEIND{c.clear()};}
};
// priority_queue⽆迭代器

可以看到,成员变量的定义方式和之前的stack差不太多;如果一定要说有什么可讲的话,我觉得是这两个构造函数,区别就在于有无将comp(仿函数)显式地给定。就这样,我们使用vector<int>作为底层容器,一个仿函数以及一系列C++提供的有关heap的函数(make_heap(),push_heap(),pop_heap())就实现了一个优先队列了。

相关文章:

C++手撕STL-其叁

Deque 今天我们进入新的容器&#xff1a;deque&#xff0c;一般叫做双端队列。 比起传统的先入先出的队列queue&#xff0c;deque的出场率显然要低得多&#xff0c;事实上deque比起queue来说最大的特点就是多了一个push_front()和pop_front()&#xff0c;其他并没有太多不同。…...

AI大模型-window系统CPU版安装anaconda以及paddle详细步骤-亲测有效

window系统CPU版安装anaconda以及paddle详细步骤-亲测有效 一 安装anaconda 下载地址:anaconda下载 下载成功后,选择非C盘安装,按提示安装即可修改镜像文件 安装成功后,运行anaconda软件,若提示更新则点击更新,更新完后,修改镜像文件 找到用户目录下的.condarc文件,覆…...

UML概览

&#x1f970;名片&#xff1a; &#x1f433;作者简介&#xff1a;乐于分享知识的大二在校生 &#x1f333;本系列专栏: (点击直达)统一建模语言UML &#x1fae3;致读者&#xff1a;欢迎评论与私信,对于博客内容的疑问都会尽量回复哒!!! 本文序&#xff1a; ⛰️本文介绍&…...

影刀填写输入框(web) 时出错: Can not convert Array to String

环境&#xff1a; 影刀5.26.24 Win10专业版 问题描述&#xff1a; [错误来源]行12: 填写输入框(web) 执行 填写输入框(web) 时出错: Can not convert Array to String. 解决方案&#xff1a; 1. 检查变量内容 在填写输入框之前&#xff0c;打印BT和NR变量的值&#xff…...

LLMs可在2位精度下保持高准确率

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…...

C语言高频面试题——结构体和联合体区别

在 C 语言中&#xff0c;结构体&#xff08;struct&#xff09; 和 联合体&#xff08;union&#xff09; 是两种重要的复合数据类型&#xff0c;用于组织和管理多个相关的变量。尽管它们在语法上有些相似&#xff0c;但在内存布局、用途和行为上有显著的区别。以下是详细的对比…...

App爬虫工具篇-mitmproxy

mitmproxy 是一个支持 HTTP 和 HTTPS 的抓包程序,类似 Fiddler、Charles 的功能,它通过控制台的形式和ui界面的方式 此外,mitmproxy 还有两个关联组件,一个是 mitmdump,它是 mitmproxy 的命令行接口,利用它可以对接 Python 脚本,实现监听后的处理;另一个是 mitmweb,它…...

配置openjdk调试环境

先决条件 首先在Ubuntu 18.04上编译SlowDebug版本的openjdk。注意&#xff0c;这里我选择的是x86处理器的电脑。苹果M系列属于ARM芯片&#xff0c;指令集不一样。由于我在苹果上进行垃圾回收调试的时候会报SIGILL错误。为了了解JVM的内部工作原理&#xff0c;不要在这种问题上…...

加油站小程序实战教程13充值规则配置

目录 1 创建数据源2 搭建管理功能最终效果 我们目前已经实现了会员的注册以及登录功能&#xff0c;有了基础的认证之后就进入到了业务部分的开发。会员的话首先是可以进行充值&#xff0c;在充值的时候通常会有一定的赠送&#xff0c;本篇我们来开发一下充值规则的配置功能。 1…...

jQuery — 总结

介绍 jQuery是一款高效、轻量级的JavaScript库&#xff0c;旨在简化网页开发中的常见任务。自2006年发布以来&#xff0c;它凭借直观的语法和强大的功能迅速成为前端开发的标配工具。其核心设计理念是“写更少&#xff0c;做更多”&#xff0c;通过封装复杂的原生JavaScript操作…...

【信息安全工程师备考笔记】第二章 网络信息安全概述

第二章 网络攻击原理与常用方法 2.1 网络攻击概述 概念&#xff1a;损害网络 系统安全属性 的危害行为 危害行为基本类型 信息泄露攻击&#xff08;机密性&#xff09;完整性破坏攻击&#xff08;完整性&#xff09;拒绝服务攻击&#xff08;可用性&#xff09;非法使用攻击…...

国家自然科学基金答辩ppt制作案例模板下载

国家自然科学基金 National Natural Science Foundation of China 支持基础研究&#xff0c;坚持自由探索&#xff0c;发挥导向作用&#xff0c;发现和培养科学技术人才&#xff0c;促进科学技术进步和经济社会协调发展&#xff0c;逐渐形成和发展了由研究项目、人才项目和环境…...

代码随想录第三十七天|华为秋季笔试真题230823

刷题小记&#xff1a; 主要偏向扎实编码基础的考察&#xff0c;但貌似近些年题目难度有所提高&#xff0c;仅供参考。 卡码网136.获取连通的相邻节点列表&#xff08;卡码网136.获取连通的相邻节点列表&#xff09; 题目分析&#xff1a; 题目描述&#xff1a; 存在N个转发…...

KUKA机器人KR 3 D1200 HM介绍

KUKA KR 3 D1200 HM是一款小型机器人&#xff0c;型号中HM代表“Hygienic Machine&#xff08;卫生机械&#xff09;用于主副食品行业”&#xff0c;也是一款并联机器人。用于执行高速、高精度的抓取任务。这款机器人采用食品级不锈钢设计&#xff0c;额定负载为3公斤&#xff…...

从零开始创建MCP Server实战指南

一、MCP协议核心概念 1.1 什么是MCP&#xff1f; MCP&#xff08;Model Context Protocol&#xff09; 是一个标准化的“沟通规则”&#xff0c;由公司Anthropic提出&#xff0c;专门用于让大语言模型&#xff08;LLM&#xff0c;比如通义千问、ChatGPT等&#xff09;与外部工…...

C语言教程(十二):C 语言数组详解

一、引言数组的基本概念 数组是一组具有相同数据类型的元素的集合&#xff0c;这些元素在内存中连续存储。通过一个统一的数组名和下标来访问数组中的每个元素。使用数组可以方便地处理大量相同类型的数据&#xff0c;避免为每个数据单独定义变量。 二、一维数组 2.1 数组的…...

Linux[基础指令][2]

Linux[基础指令][2] cp(复制) 格式:cp [-rf] 源文件 {普通文件,目录} 拷贝 cp -r 递归拷贝目录 蓝色为目录,白色为具体文件 拷贝后面加一个不存在的文件会新建文件再拷贝 cp -ir -i是覆盖的时候询问 如果目标文件存在就会覆盖原有文件 mv(重命名/剪切) 格式:mv 源文件…...

MySQL_MCP_Server_pro接入cherry_studio实现大模型操作数据库

大模型直接与数据库交互&#xff0c;实现基本增删改查操作。首先贴下代码地址&#xff1a; https://github.com/wenb1n-dev/mysql_mcp_server_pro 安装环境&#xff1a;win10 1、下载代码 git clone https://github.com/wenb1n-dev/mysql_mcp_server_pro 2、使用conda创建…...

linux命令集

命令 grep -r --includeAndroid.bp libcfs ./ ​参数说明 选项/参数作用-r递归搜索子目录。--includeAndroid.bp仅搜索名为 Android.bp 的文件&#xff08;精确匹配文件名&#xff09;。libcfs要搜索的关键字&#xff08;单引号包裹特殊字符如 以避免被 Shell 解析&#xff…...

数据结构:链表

链表的概念及结构&#xff1a; 链表的概念&#xff1a; 链表是一种物理储存结构上非连续的储存结构&#xff0c;数据元素的逻辑顺序是通过引用链接次序实现的 那物理存储结构连续是什么意思&#xff1f; 之前我们讲过顺序表&#xff0c;顺序表的底层是数组&#xff0c;如下…...

【高并发内存池】从零到一的项目之高并发内存池整体框架设计及thread cache设计

个人主页 &#xff1a; zxctscl 专栏 【C】、 【C语言】、 【Linux】、 【数据结构】、 【算法】 如有转载请先通知 文章目录 前言1. 高并发内存池整体框架设计2. 高并发内存池--thread cache2.1 定长内存池的问题2.2 整体框架2.3 自由链表2.4 thread cache哈希桶的对齐规则2.5…...

电气动调节单座V型球阀带阀杆节流套沟槽孔板的作用-耀圣

电气动调节单座V球阀杆节流套是阀门中的一个重要组件&#xff0c;主要用于调节和控制流体介质的流量、压力或流速&#xff0c;同时兼具导向、密封和稳定阀杆运动降低流速减少冲刷的作用。以下是其具体功能和应用场景的详细说明&#xff1a; 1. 节流与流量控制** 作用原理**&am…...

vscode使用笔记

文章目录 安装快捷键 vscode是前端开发的一款利器。 安装 快捷键 ctrlp # 查找文件(和idea的双击shift不一样) ctrlshiftf # 搜索内容...

基于 SpringAI 整合 DeepSeek 模型实现 AI 聊天对话

目录 1、Ollama 的下载配置 与 DeepSeek 的本地部署流程 1.1 下载安装 Ollama 1.2 搜索模型并进行本地部署 2、基于 SpringAI 调用 Ollama 模型 2.1 基于OpenAI 的接口规范&#xff08;其他模型基本遵循&#xff09; 2.2 在 IDEA 中进行创建 SpringAI 项目并调用 DS 模型 3、基…...

Idea创建项目的搭建方式

目录 一、普通Java项目 二、普通JavaWeb项目 三、maven的JavaWeb项目 四、maven的Java项目 一、普通Java项目 1. 点击 Create New Project 2. 选择Java项目&#xff0c;选择JDK&#xff0c;点击Next 3. 输入项目名称&#xff08;驼峰式命名法&#xff09;&#xff0c;可选…...

【MATLAB第115期】基于MATLAB的多元时间序列的ARIMAX的预测模型

【MATLAB第115期】基于MATLAB的多元时间序列的ARIMAX的预测模型 ‌一、简介 ARIMAX‌&#xff08;Autoregressive Integrated Moving Average with eXogenous inputs&#xff09;模型是一种结合自回归&#xff08;AR&#xff09;、差分&#xff08;I&#xff09;、移动平均&a…...

【以太网安全】——防护高级特性配置总结

目前网络中以太网技术的应用非常广泛、然后、各种网络攻击的纯在&#xff08;例如针对ARP DHCP 等攻击&#xff09;不仅造成了网络合法用户无法正常访问网络资源、而且对网络信息安全构成严重威胁、以下配置是对局域网安全配置命令做详解 主要的安全威胁 MAC攻击:泛洪、欺骗 …...

微信小程序 van-dropdown-menu

点击其他按钮&#xff0c;关闭van-dropdown-menu下拉框 DropdownMenu 引入页面使用index.wxmlindex.scssindex.ts(重点)index.ts(全部) DropdownMenu 引入 在app.json或index.json中引入组件 "usingComponents": {"van-dropdown-menu": "vant/weapp…...

再见 Smartdaili,你好 Decodo!

我们将翻开新的篇章&#xff0c;推出新的名称以及更好的代理和刮擦解决方案。了解我们如何帮助全球用户构建、测试和扩展他们的公共网络数据项目。 Smartproxy&#xff0c;即后来的Smartdaili&#xff0c;由一个行业专业人士和企业家团队于2018年创立&#xff0c;其使命是创建一…...

海量文本中的词语距离:在 O(n) 时间内找到最近的词对

想象一个巨大的日志文件、一部鸿篇巨著或者网络爬虫抓取的数据——它们可能达到 TB 级别。现在&#xff0c;假设你需要找出两个特定的词&#xff08;比如 词语1​ 和 词语2​&#xff09;在这段庞大文本中出现时&#xff0c;彼此“靠得最近”的距离是多少。 挑战&#xff1a; …...

TextCNN 模型文本分类实战:深度学习在自然语言处理中的应用

在自然语言处理&#xff08;NLP&#xff09;领域&#xff0c;文本分类是研究最多且应用最广泛的任务之一。从情感分析到主题识别&#xff0c;文本分类技术在众多场景中都发挥着重要作用。最近&#xff0c;我参与了一次基于 TextCNN 模型的文本分类实验&#xff0c;从数据准备到…...

前台调用接口的方式及速率对比

一、引言 在现代 Web 开发中&#xff0c;前台与后台的数据交互至关重要&#xff0c;而调用接口是实现这一交互的关键手段。不同的接口调用方式在速率上可能存在差异&#xff0c;这会影响用户体验和应用性能。本文将详细介绍几种常见的前台调用接口方式&#xff0c;并对它们的速…...

高级java每日一道面试题-2025年4月21日-基础篇[反射篇]-如何使用反射获取一个类的所有方法?

如果有遗漏,评论区告诉我进行补充 面试官: 如何使用反射获取一个类的所有方法&#xff1f; 我回答: 在Java中&#xff0c;反射是一种强大的机制&#xff0c;允许程序在运行时检查或“反射”自身&#xff0c;从而动态地操作类、字段、方法和构造函数等。这在需要动态调用方法…...

tomcat集成redis实现共享session

中间件&#xff1a;Tomcat、Redis、Nginx jar包要和tomcat相匹配 jar包&#xff1a;commons-pool2-2.2.jar、jedis-2.5.2.jar、tomcat-redis-session-manage-tomcat7.jar 配置Tomcat /conf/context.xml <?xml version1.0 encodingutf-8?> <!--Licensed to the A…...

2.6 递归

递归 特性&#xff1a; >.一递一归 >.终止条件 一般为&#xff1a;0 1 -1 #测试函数的返回值为函数 def test_recursion():return test_recursion() print(test_recursion()) RecursionError: maximum recursion depth exceeded #案例&#xff1a;计算 …...

鸿蒙应用开发:如何修改APP名称与APP的图标

如何修改APP的名称&#xff1f; 修改APP的名称需要修改entry/src/main/resources/base/element/string.json文件 将EntryAbility_label的value修改为“需要修改成的名字”。 文件目录&#xff1a; 代码修改&#xff1a; {"string": [{"name": "modu…...

AI 模型在前端应用中的典型使用场景和限制

典型使用场景 1. 智能表单处理 // 使用TensorFlow.js实现表单自动填充 import * as tf from tensorflow/tfjs; import { loadGraphModel } from tensorflow/tfjs-converter;async function initFormPredictor() {// 加载预训练的表单理解模型const model await loadGraphMod…...

前端性能优化全攻略:JavaScript 优化、DOM 操作、内存管理、资源压缩与合并、构建工具及性能监控

1 为什么需要性能优化&#xff1f; 1.1 性能优化的核心价值&#xff1a;用户体验与业务指标 性能优化不仅是技术层面的追求&#xff0c;更是直接影响用户体验和业务成败的关键因素。 用户体验&#xff08;UX&#xff09;&#xff1a; 响应速度&#xff1a;用户期望页面加载时…...

使用 acme.sh 自动更新 SSL 证书的指南

上篇文章讲了一下 如何利用acme.sh来申请ssl&#xff0c;但没有讲3个月到期后 如何续期&#xff0c;续期的时候会碰到什么问题&#xff1f; 1.查看当前的当前签发域名的到期时间 acme.sh list 2.重新申请ssl acme.sh --issue --dns dns_namesilo -d xxx.ai -d *.xxx.ai --dns…...

查看Spring Boot项目所有配置信息的几种方法,包括 Actuator端点、日志输出、代码级获取 等方式,附带详细步骤和示例

以下是查看Spring Boot项目所有配置信息的几种方法&#xff0c;包括 Actuator端点、日志输出、代码级获取 等方式&#xff0c;附带详细步骤和示例&#xff1a; 1. 使用Spring Boot Actuator Actuator是Spring Boot提供的监控和管理工具&#xff0c;包含/configprops端点可查看…...

C++与C

文章目录 C与C命令空间const关键字new/delete表达式引用&#xff08;重点&#xff09;概念引用的本质引用的使用场景引用作为函数的参数引用作为函数的返回值 总结 强制转换函数重载extern "C"默认参数 bool类型inline&#xff08;内联&#xff09;函数异常处理&…...

Nginx​中间件的解析

目录 一、Nginx的核心架构解析 二、Nginx的典型应用场景 三、Nginx的配置优化实践 四、Nginx的常见缺陷与漏洞 一、Nginx的核心架构解析 ​​事件驱动与非阻塞IO模型​​ Nginx采用基于epoll/kq等系统调用的事件驱动机制&#xff0c;通过异步非阻塞方式处理请求&#xff0c;…...

Ansys Zemax | 在 MATLAB 中使用 ZOS-API 的技巧

附件下载 联系工作人员获取附件 本文将介绍一些在MATLAB中使用 ZOS-API 的技巧&#xff0c;以提高您的工作效率并充分利用 ZOS-API 的功能。 简介 OpticStudio开发了应用程序接口 (API) &#xff0c;用户可以使用API与不同的脚本环境进行连接和交互。使用API&#xff0c;用…...

js 生成pdf 并上传文件

js 生成pdf 并上传文件 使用 JsPDF html2Canvas 代码直接使用 注意注释 import JsPDF from jspdf import html2Canvas from html2canvas // 上传文件的方法 import { handleUploadImage } from /utils/uploadQuillEditdownPDF() {// 要打印元素的idconst cloneDom document.…...

刷刷刷刷刷sql题

NSSCTF 【SWPUCTF 2021 新生赛】easy_sql 这题虽然之前做过&#xff0c;但为了学习sql&#xff0c;整理一下就再写一次 打开以后是杰哥的界面 注意到html网页标题的名称是 “参数是wllm” 那就传参数值试一试 首先判断注入类型&#xff08;数字型或字符型&#xff09; 传1 …...

JavaScript 中的 this 及 this 指向的改变方法

在 JavaScript 的世界里&#xff0c;this是一个既强大又容易让人困惑的概念。它的指向在不同的函数调用场景下会动态变化&#xff0c;而call()、apply()和bind()这三个方法则为我们提供了精确控制this指向的能力。本文将从基础概念出发&#xff0c;结合具体案例&#xff0c;带大…...

安卓模拟器绕过检测全解析:雷电、MuMu、蓝叠、逍遥、夜神与WSA完整指南

安卓模拟器绕过检测全解析&#xff1a;雷电、MuMu、蓝叠、逍遥、夜神与WSA完整指南 模拟器过检测合集雷电mumu蓝叠逍遥夜神WSA 转自风车2025 前言 随着手机游戏和应用的普及&#xff0c;越来越多的用户选择在PC上通过模拟器来运行安卓应用。然而&#xff0c;许多应用和游戏为…...

VSCode中安装GitGraph

前提是先安装git&#xff0c;官方下载地址&#xff1a;Git - Downloads 1. 在VSCode中安装GitGraph插件 2. 文件->首选项->设置&#xff0c;打开设置界面&#xff0c;在设置界面搜索git path 3. 打开配置文件配置git安装路径&#xff1a; 4. 打开源代码管理&#xff0c;…...

StartAI「万物迁移」功能设计师实操教程:模特换衣场景应用

一、功能核心优势解析 智能识别与场景融合 基于迁移学习算法&#xff0c;精准定位服装轮廓&#xff08;支持复杂材质如蕾丝、镂空设计&#xff09;&#xff0c;自动匹配目标场景的光影方向与色温。 效率革命 传统PS手动换衣需2-3小时&#xff0c;使用万物迁移可压缩至2-5分…...

【RK3588 嵌入式图形编程】-SDL2-扫雷游戏-放置标记

放置标记 文章目录 放置标记1、概述2、更新Globals.h3、放置标记4、渲染标记5、标记计数6、完整代码7、改进建议8、总结在本文中,我们实现标记放置和跟踪以完成的扫雷游戏项目。 1、概述 在我们扫雷游戏文章系列的最后部分中,我们将添加玩家在可疑的地雷位置放置标记的功能。…...