一文速通stack和queue的理解与使用
C++STL之stack和queue
- 1.stack
- 1.1.stack的基本概念
- 1.2.stack的接口
- 2.queue
- 2.1.queue的基本概念
- 2.2.queue的接口
- 3.priority_queue
- 3.1.priority_queue的基本概念
- 3.2.priority_queue的接口
- 3.3.仿函数
- 4.容器适配器
- 5.deque
- 5.1.deque的简单了解
- 5.2.deque的优缺点
🌟🌟hello,各位读者大大们你们好呀🌟🌟
🚀🚀系列专栏:【C++的学习】
📝📝本篇内容:stack;stack的基本概念;stack的接口;queue;queue的基本概念;queue的接口;priority_queue;priority_queue的基本概念;priority_queue的接口;仿函数;容器适配器;deque;deque的简单了解;deque的优缺点
⬆⬆⬆⬆上一篇:一文搞懂反向迭代器之C++模拟实现list
💖💖作者简介:轩情吖,请多多指教(> •̀֊•́ ) ̖́-
1.stack
1.1.stack的基本概念
在我们C++的STL中也实现了栈,也就是stack,它的特性是“先进后出”(First In Last Out,FILO)。允许插入和删除的一端称为栈顶,另一端称为栈底。stack是作为容器适配器被实现的,容器适配器即是对特定类封装作为底层的容器,并提供一组特定的成员函数来访问其元素,将特定的类作为底层的,元素特定容器的尾部(即栈顶)被压入和弹出。
在底层的容器需要有这些成员函数进行操作:empty()、back()、push_back()、pop_back()
我们STL标准库中vector、list都是符合的,但是默认没有为stack指定特定的容器,底层都是使用的deque。
1.2.stack的接口
stack | 函数说明 |
---|---|
stack() | 构造一个空的栈 |
size_t size()const; | 栈有效元素的个数 |
value_type& top(); | 栈顶的值 |
void push (const value_type& val); | 压入一个数据,俗称压栈 |
void pop(); | 出栈,将数据弹出 |
bool empty()const; | 是否为空 |
#include <iostream>
#include <stack>
using namespace std;
int main()
{//默认构造stack<int> st;//压栈st.push(10);st.push(11);st.push(12);//查看大小cout <<"stack size:" << st.size() << endl;//3//查看栈顶元素cout <<"stack top:"<< st.top() << endl;//12//出栈st.pop();st.pop();st.pop();if (st.empty())//true{cout << "stack is empty" << endl;}return 0;
}
还可以指定容器,对于deque我们稍后再讲,以及对于它的底层实现有不理解的可以看我下一篇博客
#include <stack>
#include <iostream>
#include <vector>
#include <list>
using namespace std;
int main()
{stack<int, list<int>> st1;//底层容器使用的是liststack<int, vector<int>> st2;//底层容器使用的是vectorreturn 0;
}
2.queue
2.1.queue的基本概念
谈到stack就必定会谈到queue,queue就是队列。它的特性是“先进先出”(First In First Out,FIFO),它与stack不同,stack只能在一端操作,但是queue不一样,它的插入操作(进队)只能在表尾,队列的删除操作(出队)只能在表头。能够进行插入元素的一端我们称为队尾,允许删除元素的一端称为队头或队首。
底层和stack一样,是使用了其他的容器来适配,该容器需要支持这些操作:empty()、size()、front()、back()、push_back()、pop_front()。
我们的list是符合这个条件的(vector没有头插,效率太低),但是底层默认使用的是deque
2.2.queue的接口
stack | 函数说明 |
---|---|
queue() | 构造一个空的队列 |
bool empty()const; | 判断队列是否为空 |
size_t size()const; | 返回队列有效元素的个数 |
value_type& front(); | 返回队头元素的引用 |
value_type& back(); | 返回队尾元素的引用 |
void push (const value_type& val); | 将元素在队尾入队列 |
void pop(); | 将队头元素出队列 |
#include <iostream>
#include <queue>
using namespace std;
int main()
{//默认构造queue<int> q;//入队列q.push(10);q.push(11);q.push(12);q.push(13);//有效元素个数cout << "size:" << q.size() << endl;//4//队头元素cout << "front:" << q.front() << endl;//10//队尾元素cout << "back:" << q.back() << endl;//13//出队列q.pop();q.pop();q.pop();q.pop();//判空if (q.empty())//true{cout << "queue is empty" << endl;}return 0;
}
3.priority_queue
3.1.priority_queue的基本概念
priority_queue是优先级队列,它也是一种容器适配器,它每一次插入元素,底层就会进行调整,保证它的第一个元素是最大的(最小的)。
它类似于堆,在堆中可以随时插入元素,并且只能检索最大的堆元素(优先级队列中位于顶部的元素)
底层的容器应该是能够支持随机访问迭代器访问的,并且要支持以下操作:empty()、size()、front()、push_back()、pop_back()
在标准容器中,我们的deque和vector都是符合要求的,但是如果没有自己指定容器,那么默认为vector,需要支持随机访问迭代器,以便始终在内部保持堆结构。容器适配器通过在需要时自动调用算法函数make_heap、push_heap和pop_heap来自动完成此操作。
我们可以看到其模板参数中还有一个Compare,这其实就是为了使用者能够根据自己的需求,选择大堆还是小堆
我稍微看图来理解一下,具体的实现看我模拟实现的文章,这边主要还是使用为主
上图假设为vector中所开辟的空间,可能看上去没有什么,那么转换为树型结构呢?如下图
可以根据公式来看一下:
若i>0,i位置结点的双亲序号:(i-1)/2=parent;i=0,i为根节点编号,无双亲结点
设n为数组的大小,若2i+1<n,左孩子序号:2i+1=leftchild;2i+1>=n否则无左孩子
设n为数组的大小,若2i+2<n,右孩子序号:2i+2=rightchild;2i+2>=n否则无右孩子
可以看到我们的树中,根节点的元素是最小的,其余子树的根节点的元素也是小于孩子节点元素的。
这个事我们的小根堆,大根堆就是反过来,根节点的元素是最大的,其余子树的根节点的元素也是大于孩子节点元素的
我们的priority_queue默认情况下是大堆,其底层是按照小于比较的
3.2.priority_queue的接口
priority_queue | 函数说明 |
---|---|
priority_queue(); | 构造一个空的优先级队列 |
priority_queue(InputIterator first, InputIterator last); | 使用迭代器构造 |
bool empty() const; | 判断优先级队列是否为空 |
size_t size()const; | 优先级队列有效元素的个数 |
const value_type& top() const; | 返回优先级队列中最大(最小)的元素,即堆顶的元素 |
void push (const value_type& val); | 往优先级队列中插入元素 |
void pop(); | 删除优先级队列中最大(最小)的元素,即堆顶的元素 |
#include <iostream>
#include <queue>
using namespace std;
int main()
{//默认构造,大堆priority_queue<int> pq;//插入元素pq.push(10);pq.push(1);pq.push(32);pq.push(23);pq.push(16);//priority_queue的有效元素个数cout << "priority_queue size:" << pq.size() << endl;//5//最大元素cout<<"priority_queue top1:"<<pq.top()<<endl;//32//删除堆顶元素pq.pop();//现在堆顶是第二大元素cout << "priority_queue top2:" << pq.top() << endl;//23pq.pop();pq.pop();pq.pop();pq.pop();//叛空if (pq.empty())//true{cout << "priority_queue is empty" << endl;}return 0;
}
3.3.仿函数
前面我们提到过,我们的优先级队列可以通过传递模板参数改变到底是存储大堆还是小堆,接下来先演示一下
可以看到我们的优先级队列的模板参数传递时多了一个greater类,它是在functional头文件中的,它其实就是一个普通的类中重载了运算符(),这是用来优先级队列内部改变比较的方法,从而达到改变大小堆的切换,还是那句话,具体的实现看我的模拟实现文章,这边主要讲述使用
当优先级队列所存储的元素是自定义类型的时候,那么这个自定义类型需要重载比较运算符,这是因为优先级队列的底层为了保证堆的特性,进行比较调整
下面是演示代码:
#include <iostream>
#include <queue>
#include <functional>
using namespace std;
struct Date
{Date(int year=0,int month=0,int day=0):_year(year),_month(month),_day(day){}//对于自定义的类,需要重载小于<、大于>bool operator>(const Date& d)const{if (_year > d._year){return true;}else if (_year == d._year && _month > d._month){return true;}else if (_year == d._year && _month == d._month && _day > d._day){return true;}return false;}bool operator<(const Date& d)const{if (_year < d._year){return true;}else if (_year == d._year && _month < d._month){return true;}else if (_year == d._year && _month == d._month && _day < d._day){return true;}return false;}int _year;int _month;int _day;};namespace lnb
{//这里便于理解,模拟实现一下greater,和lesstemplate<class T>struct greater{bool operator()(const T& x,const T& y)const//重载运算符(){return x > y;}};template<class T>struct less{bool operator()(const T& x, const T& y)const{return x < y;}};}
int main()
{priority_queue<Date, vector<Date>, lnb::less<Date>> pq;pq.push(Date(2024, 1, 1));pq.push(Date(2024, 2, 5));pq.push(Date(2024, 12, 2));pq.push(Date(2024, 7, 9));pq.push(Date(2024, 1, 4));const Date& d = pq.top();//注意top()的返回值是const属性的cout << "priority_queue top:" <<d._year<<"/"<<d._month<<"/"<<d._day<<endl;// 2024/12/ 2return 0;
}
上面的代码也实现了一下greater和less类,默认情况下,我们的priority_queue用来比较的类是less。
大家把一个类中重载了()运算符的类叫做仿函数,为什么呢?因为它的使用像一个函数,使用类来模拟函数行为的技术,也叫作函数对象
//一个简单的仿函数使用
#include <iostream>
using namespace std;
struct Compare
{bool operator()(const int& x, const int& y)const{return x > y;}
};
int main()
{//bool flag=Compare()(1, 2);//使用匿名对象来直接调用Compare com;bool flag=com(1, 2);.//像函数一样调用if (flag){cout << "大于" << endl;}else{cout << "小于" << endl;}return 0;
}
4.容器适配器
在我们前面的讲述的stack、queue、priority_queue都是容器适配器。
适配器是一种设计模式,该种模式是将一个类的接口转换成客户希望的另外一个接口。
虽然stack和queue中也可以存放元素,但在STL中并没有将其划分在容器的行列,而是将其称为容器适配器,这是因为stack和队列只是对其他容器的接口进行了包装,STL中stack和queue默认使用deque,priority_queue默认使用vector
5.deque
5.1.deque的简单了解
之前提及了那么多次的deque,现在该讲它了,它的底层是非常复杂的,我们只需要对它有个简单的了解即可,如果想要学习具体的完整源码可以去看候捷老师的STL源码剖析,如果需要电子版,可以私信我
deque是一种双向开口的连续线性空间,能够在头尾两端分别做元素的插入和删除操作,和vector相比,vector只是单向开口的连续线性空间,虽然从技术观点上来说,vector也可以在首尾两端进行操作,但是它的头部操作需要进行移动数据,效率极差。我们的deque能够在常数时间内对头部进行操作,并且我们的deque没有所谓容量的概念,因为它是动态地以分段连续空间组合而成,随时可以增加一段新的空间并链接起来。deque的迭代器也是随机迭代器,能够支持随机访问,但是其底层是经过了封装的,极其复杂。
deque采用一块连续的map作为主控,map是一小块连续的空间,其中的每一个元素都是指针,指向另一段连续线性空间,称为缓冲区。所以说deque并不是真正连续的空间,而是由一段段连续的小空间拼接而成的,实际deque类似于一个动态的二维数组。
我们来看一下STL源码剖析中的图来更好的理解
// 见 deque_buf_size()。BufSize 默认值为 0 的唯一理由是为了闪避某些
// 编译程序在处理常数算式(constant expressions)时的臭虫。
// 默认使用alloc为配置器
template <class T, class Alloc = alloc, size_t BufSiz = 0>
class deque {
public: // Basic typestypedef T value_type;typedef value_type* pointer;typedef size_t size_type;public: // Iteratorstypedef deque_iterator<T, T&, T*, BufSiz> iterator;protected: // Internal typedefs// 元素的指针的指针(pointer of pointer of T)typedef pointer* map_pointer;protected: // Data membersiterator start; // 表现第一个节点。iterator finish; // 表现最后一个节点。map_pointer map; // 指向 map,map是块连续空间,// 其每个元素都是个指针,指向一个节点(缓冲区)size_type map_size; // map内有多少指标...
};
上面的代码也是摘取自STL源码剖析,其中我们可以通过图和代码有个大致的了解,map中存储了指向各个缓冲区的指针,通过map我们就可以找到任意一个元素。其中比较重要的就是还有它的迭代器。
我们依旧集合图片和代码来看
template <class T, class Ref, class Ptr, size_t BufSiz>
struct deque_iterator { // 未继承 std::iteratortypedef deque_iterator<T, T&, T*, BufSiz> iterator;typedef deque_iterator<T, const T&, const T*, BufSiz> const_iterator;static size_t buffer_size(){return deque_buf_size(BufSiz,sizeof(T));}// 未继承 std::iterator,所以必须自行撰写五个必要的迭代器相应型别typedef random_access_iterator_tag iterator_category; // (1)typedef T value_type; // (2)typedef Ptr pointer; // (3)typedef Ref reference; // (4)typedef size_t size_type;typedef ptrdiff_t difference_type; // (5)typedef T** map_pointer;typedef deque_iterator self;//保持与容器的联结T* cur; // 此迭代器所指之缓冲区中的现行(current)元素T* first; // 此迭代器所指之缓冲区的头T* last; // 此迭代器所指之缓冲区的尾(含备用空间)map_pointer node; // 指向管控中心...
};
我们的迭代器内部的四个成员,能够保证找到任意一个元素。我们可以通过node来进行跳转到上一个或下一个缓冲区,通过first和last来保证因为插入或删除导致越界访问,cur指向当前访问的元素。
在我们deque中,也包含了start和finish两个迭代器,它们分别是begin()和end()的返回值,所以说要注意finish中cur的指向。因为迭代器访问会不停的往前迭代,那么最后的终止条件是遇到最后一个元素的下一个位置,所以说finish中的cur指向并不是最后一个元素。
看一下下面的这张图来理解一下,一个迭代器类型的对象的指向:
5.2.deque的优缺点
优点:
①相比vector来说,扩容的代价比较低,vector扩容需要搬用元素,而deque则只需要增加一段线性空间即可
②deque的头插头删、尾插尾删效率高,我们的vector在头插时可能需要扩容并且还要移动元素,因此效率极差
③支持随机访问,我们的list却没法做到
④其底层是连续空间,空间利用率比较高,不需要存储额外字段,这点list也做不到
缺点:
①deque的中间插入和删除就不是很好的了,因为这也是有可能需要移动大量的元素
这边有两种情况:每个buff数组不一样大,效率会提高,但是会影响随机访问效率;每个buff数组固定大小,牺牲中间插入删除效率,随机访问效率就变高了。我们的SGI的STL中使用是后者,为了保证随机访问
②最主要的缺点是没有vector和list的优点极致
③但是,deque有一个致命缺陷:不适合遍历,因为在遍历时,deque的迭代器要频繁的去检测其是否移动到某段小空间的边界,导致效率低下,而序列式场景中,可能需要经常遍历,因此在实际中,需要线性结构时,大多数情况下优先考虑vector和list,deque的应用并不多,而目前能看到的一个应用就是,STL用其作为stack和queue的底层数据结构
stack和queue选择deque作为底层默认的容器是因为deque完美的避开了缺点,展现出了优点。stack和queue不需要遍历(因此stack和queue没有迭代器),只需要在固定的一端或者两端进行操作。在stack中元素增长时,deque比vector的效率高(扩容时不需要搬移大量数据),内存利用率比list高;queue中的元素增长时,deque不仅效率高;出队时,头删效率也高,比vector强,而且内存使用率高,比list强。
🌸🌸C++STL之stack和queue的知识大概就讲到这里啦,博主后续会继续更新更多C++的相关知识,干货满满,如果觉得博主写的还不错的话,希望各位小伙伴不要吝啬手中的三连哦!你们的支持是博主坚持创作的动力!💪💪
相关文章:

一文速通stack和queue的理解与使用
CSTL之stack和queue 1.stack1.1.stack的基本概念1.2.stack的接口 2.queue2.1.queue的基本概念2.2.queue的接口 3.priority_queue3.1.priority_queue的基本概念3.2.priority_queue的接口3.3.仿函数 4.容器适配器5.deque5.1.deque的简单了解5.2.deque的优缺点 🌟&…...

Antd React Form使用Radio嵌套多个Select和Input的处理
使用Antd React Form使用Radio会遇到嵌套多个Select和Input的处理,需要多层嵌套和处理默认事件和冒泡,具体实现过程直接上代码。 实现效果布局如下图 代码 <Formname"basic"form{form}labelWrap{...formItemLayoutSpan(5, 19)}onFinish{on…...
Vue - toRefs() 和 toRef() 的使用
一、toRefs() 在 Vue 3 中,toRefs()可以将响应式对象的属性转换为可响应的 refs。主要用于在解构响应式对象时,保持属性的响应性。 1. 导入 toRefs 函数 import { toRefs } from vue;2. 将响应式对象的属性转换为 ref const state reactive({count: 0,message:…...

Python3 OS模块中的文件/目录方法说明九
一. 简介 前面文章简单学习了 Python3 中 OS模块中的文件/目录的部分函数。 本文继续来学习 OS 模块中文件、目录的操作方法:os.pipe() 方法、os.popen() 方法。 二. Python3 OS模块中的文件/目录方法 1. os.pipe() 方法 os.pipe() 方法用于创建一个管道, 返回…...

OpenCV文字绘制支持中文显示
OpenCV版本:4.4 IDE:VS2019 功能描述 OpenCV绘制文本的函数putText()不支持中文的显示,网上很多方法推荐的都是使用FreeType来支持,FreeType是什么呢?FreeType的官网上有介绍 FreeType官网 https://www.freetype.or…...

opengrok_windows_多工程环境搭建
目录 多工程的目录 工程代码下载和log配置 工程的索引 工程部署 工程测试 参考列表 多工程的目录 工程代码下载和log配置 工程代码下载 在每个工程的src目录下,下载工程代码,以下载pulseaudio的代码为例。 git clone gitgithub.com…...

基于ollama,langchain,springboot从零搭建知识库三【解析文档并存储到向量数据库】
安装环境 安装pgvector,先设置docker镜像源: vim /etc/docker/daemon.json {"registry-mirrors": ["https://05f073ad3c0010ea0f4bc00b7105ec20.mirror.swr.myhuaweicloud.com","https://mirror.ccs.tencentyun.com",&…...

Elasticsearch 和arkime 安装
安装一定要注意版本号,不然使用不了 这里Ubuntu使用ubuntu-20.04.6-desktop-amd64.iso elasticsearch这里使用Elasticsearch 7.17.5 | Elastic arkime这里使用wget https://s3.amazonaws.com/files.molo.ch/builds/ubuntu-20.04/arkime_3.4.2-1_amd64.deb 大家想…...
git回退
git回退 1、未使用 git add 缓存代码时 git checkout –- filepathname 放弃单个文件的修改 git checkout . 放弃所有的文件修改 此命令用来放弃掉所有还没有加入到缓存区(就是 git add 命令)的修改:内容修改与整个文件删除。但是此命令不…...

pytest+playwright落地实战大纲
前言 很久没有更新博客,是因为在梳理制作Playwright测试框架实战相关的课程内容。现在课程已经完结,开个帖子介绍下这门课程(硬广, o(〃^▽^〃)o) 课程放在CSDN学习频道, 欢迎关注~ PyTestPl…...

01-硬件入门学习/嵌入式教程-CH340C使用教程
前言 CH340C广泛应用于DIY项目和嵌入式开发中,用于USB数据转换和串口通信。本文将详细介绍CH340C的基本功能、引脚接线及使用方法。 CH340C简介 CH340C是一款USB转TTL电平转换器,可以将电脑的USB数据转换成串口数据,方便与单片机ÿ…...

小试牛刀调整Prompt,优化Token消耗
在上一篇文章 荒腔走板Mac电脑本地部署 LLM 中介绍过本地部署大模型之后,可以通过定制 prompt 来实现 domain 提取等各种各样的需求。 但是实际上,部署本地大模型 这种方式对于个人开发者来说实在是不太友好。一方面需要投入大量资金确保设备的算力足够支…...

snippets router pinia axios mock
文章目录 补充VS Code 代码片段注册自定义组件vue routerpinia删除vite创建项目时默认的文件axiosmock3.0.x版本的 viteMockServe 补充 为文章做补充:https://blog.csdn.net/yavlgloss/article/details/140063387 VS Code 代码片段 为当前项目创建 Snippets {&quo…...

Visual Studio2019调试DLL
1、编写好DLL代码之后,对DLL项目的属性进行设置,选择待注入的DLL,如下图所示 2、生成DLL文件 3、将DLL设置为启动项目之后,按F5启动调试。弹出选择注入的exe的界面之后,使用代码注入器注入步骤2中生成的dll࿰…...

深入解析:Docker 容器如何实现文件系统与资源的多维隔离?
目录 一、RootFs1. Docker 镜像与文件系统层2. RootFs 与容器隔离的意义 二、Linux Namespace1. 进程命名空间1.1 lsns 命令说明1.2 查看“祖先进程”命名空间1.3 查看当前用户进程命名空间 2. 容器进程命名空间2.1 查看容器进程命名空间列表2.2 容器进程命名空间的具体体现 三…...
vue项目中打包后的地址加载不出图片【五种解决方案】
在 Vue 项目中打包后,加载图片路径可能会出现问题,主要是因为打包后的路径与开发时的路径不同。为了确保图片可以正确加载,你可以考虑以下几种方法: 1. 使用 require 或 import 动态加载图片 如果你在 Vue 的模板或者脚本中引用…...
讯飞星火大模型将超越chatgpt?
讯飞星火大模型真的能超越ChatGPT吗? 在人工智能的世界里,新技术层出不穷,而科大讯飞最近发布的讯飞星火大模型3.0引发了不少讨论。有些人甚至大胆猜测:这个模型是否能够在某些方面超越如今广受欢迎的ChatGPT?今天,我们就来深入探讨一下这个话题,分析讯飞星火大模型3.0…...
3D Vision--计算点到平面的距离
写在前面 本文内容 计算点到平面的距离 平台/环境 python open3d 转载请注明出处: https://blog.csdn.net/qq_41102371/article/details/121482246 目录 写在前面准备Open3D代码完 准备Open3D pip install open3d代码 import open3d as o3ddef compute_points2…...
《开源与合作:驱动鸿蒙Next系统中人工智能技术创新发展的双引擎》
在当今科技飞速发展的时代,鸿蒙Next系统作为一款具有创新性和前瞻性的操作系统,为人工智能技术的发展提供了广阔的舞台。而开源和合作则是推动鸿蒙Next系统中人工智能技术创新和发展的两大关键引擎。 开源:创新的源泉 代码共享与知识传播&am…...

Java 高级工程师面试高频题:JVM+Redis+ 并发 + 算法 + 框架
前言 在过 2 个月即将进入 3 月了,然而面对今年的大环境而言,跳槽成功的难度比往年高了很多,很明显的感受就是:对于今年的 java 开发朋友跳槽面试,无论一面还是二面,都开始考验一个 Java 程序员的技术功底…...

龙虎榜——20250610
上证指数放量收阴线,个股多数下跌,盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型,指数短线有调整的需求,大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的:御银股份、雄帝科技 驱动…...
day52 ResNet18 CBAM
在深度学习的旅程中,我们不断探索如何提升模型的性能。今天,我将分享我在 ResNet18 模型中插入 CBAM(Convolutional Block Attention Module)模块,并采用分阶段微调策略的实践过程。通过这个过程,我不仅提升…...

【项目实战】通过多模态+LangGraph实现PPT生成助手
PPT自动生成系统 基于LangGraph的PPT自动生成系统,可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析:自动解析Markdown文档结构PPT模板分析:分析PPT模板的布局和风格智能布局决策:匹配内容与合适的PPT布局自动…...
在Ubuntu中设置开机自动运行(sudo)指令的指南
在Ubuntu系统中,有时需要在系统启动时自动执行某些命令,特别是需要 sudo权限的指令。为了实现这一功能,可以使用多种方法,包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法,并提供…...
Neo4j 集群管理:原理、技术与最佳实践深度解析
Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...

Module Federation 和 Native Federation 的比较
前言 Module Federation 是 Webpack 5 引入的微前端架构方案,允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...
JavaScript基础-API 和 Web API
在学习JavaScript的过程中,理解API(应用程序接口)和Web API的概念及其应用是非常重要的。这些工具极大地扩展了JavaScript的功能,使得开发者能够创建出功能丰富、交互性强的Web应用程序。本文将深入探讨JavaScript中的API与Web AP…...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...

通过 Ansible 在 Windows 2022 上安装 IIS Web 服务器
拓扑结构 这是一个用于通过 Ansible 部署 IIS Web 服务器的实验室拓扑。 前提条件: 在被管理的节点上安装WinRm 准备一张自签名的证书 开放防火墙入站tcp 5985 5986端口 准备自签名证书 PS C:\Users\azureuser> $cert New-SelfSignedCertificate -DnsName &…...
十九、【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建
【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建 前言准备工作第一部分:回顾 Django 内置的 `User` 模型第二部分:设计并创建 `Role` 和 `UserProfile` 模型第三部分:创建 Serializers第四部分:创建 ViewSets第五部分:注册 API 路由第六部分:后端初步测…...