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

【C++】list底层封装和实现

目录

  • 节点类
    • 基本框架
    • 构造函数
  • list类
    • 构造函数
    • 拷贝构造函数
    • 赋值重载
    • 析构函数
  • 迭代器类
    • 前言(string和vector的区别)
    • 迭代器模版参数的说明
    • 构造函数
    • ++运算符重载
    • - -运算符的重载
    • ==运算符重载
    • !=运算符的重载
    • *运算符的重载
    • ->运算符的重载
  • 迭代器相关函数
  • 插入和删除函数
    • insert
    • erase函数
    • push_fron, pop_back, pop_front
  • 其他函数
    • size函数
    • clear函数
    • swap函数
  • list的sort vs 库的sort
    • vector和list的排序效率
  • 从迭代器类重新理解封装
  • end

节点类

基本框架

template<class T>
struct list_node
{T _data;list_node<T>* _next;list_node<T>* _prev;
};
  • 这个框架很简单,具体的我在数据结构模拟实现链表那个章节已经详细讲过,如果需要请去复习一下【手撕数据结构】拿捏双向链表

构造函数

template<class T>
struct list_node
{T _data;list_node<T>* _next;list_node<T>* _prev;list_node(const T& x = T())	//别忘了写缺省参数:_data(x),_next(nullptr),_prev(nullptr){}
};
  • 这里我们就用初始化列表对链表节点对象进行初始化,对节点存储的值用匿名对象进行缺省参数赋值。前后节点指针初始化为空指针
  • 这里的匿名对象对于自定义类型会去调用他们的默认构造来初始化,内置类型也有构造函数就是int,float,double是0

list类

构造函数

  • 我们要清楚,我们现在实现的链表是一个循环双向链表,那么就要求逻辑结构应该如图这样

在这里插入图片描述

  • 那么就需要对链表的头结点的前后节点指针都指向他自己

那么我们的构造函数不妨这样来实现

void empty_init()
{_head = new Node(); //调用构造函数,创造节点初始化,链表是一个个节点连接起来_head->_next = _head;_head->_prev = _head;	//带头双向循环
}
  • 我们实现一个成员函数来初始化哨兵位节点

这里补充一下_head, 是链表的哨兵位节点

private:Node* _head;
  • 构造函数直接调用这个初始化函数就行了
list()
{empty_init();
}
  • 这里有同学就会有疑问,这里为啥不喝前面的string,vectori两个容器的构造一样在构造函数的初始化列表进行初始化,像下图一样
    在这里插入图片描述

因为初始化列表他只能用来初始化成员变量,_head的确是成员变量不错,但是_head->_next并不是成员变量,而是成员变量的成员。

  • 所以我们就实现一个函数来完成这些操作

拷贝构造函数

		list(const list<T>& lt){empty_init();for (auto& e : lt){push_back(e);}}
  • 在string和vector两个容器里面我已经详细讲解了拷贝构造的要求,最重要的就是要完成深拷贝。这里我们就用了push_back这个接口来完成深拷贝。
	void push_back(const T& x){Node* new_node = new Node(x); //new 可以开空间,也能调用构造函数初始化Node* tail = _head->_prev;tail->_next = new_node;new_node->_prev = tail;new_node->_next = _head;_head->_prev = new_node;	//改成_head->_prve就没有问题了_size++;}
  • 可以看到我们的push_back函数用new开了新空间,并且把对应的指针指向了新空间,这就完成了深拷贝。
  • 或许有同学疑问,为啥这_head->_prev = new_node;不写成tail = new_node
  • 原因就是tail是一个指针变量,我们改变指针变量的值是不能改变指针变量指向的值的。
    在这里插入图片描述
    在这里插入图片描述
  • 所以改变tail并不能改变_head->_prev,这里我面的本意是想把_head->_prev这个指针的指向改变

赋值重载

	list<T>& operator=(list<T> lt){swap(lt);return *this;}
  • 还记得我在前面两章说vector和string的赋值重载的时候吗,资本家思想。如果我想要得到lt的并且想扔掉原来的资源,只需要把swap一下,lt这个局部变量在调用完这个函数就会销毁。因为我现在已经把原来this的资源交换给了lt, 所以销毁lt就相当于销毁了原来this指向的资源。

析构函数

	~list(){clear();delete _head;_head = nullptr;}
  • 这里我们直接先提前看一下clear的内部实现,来了解析构函数
		void clear(){auto it = begin();while (it != end()){it = erase(it);}}
  • 可以看到就是从头结点删除到尾节点,这里的erae方法后面介绍
  • 所以析构的时候我们就只需要delete一下哨兵节点就行了

迭代器类

前言(string和vector的区别)

或许很多人有疑问,为啥list迭代器还要单独实现一个类来解决,而vector和string就可以直接写出来。我们先来回顾一下vector的迭代器
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 可以看到我们不管是删除还是插入操作,如果我们想要找到下一个数据的地址,只需要简单的++或者–就行了,这就是原生指针,我们开辟空间的时候是开辟一块连续的空间
    在这里插入图片描述
  • 但是对于链表,我们是一个节点一个节点的开空间,这样开出来的空间位置是随机的是不连续的,这时候我们再想要通过简单的++或者–就找到数据就不可能了。
    在这里插入图片描述
    既然原生指针并不能找到链表的下一个节点,那么我们就需要封装一个迭代器类来完成这一系列操作。
  • 我们实现这个类的时候要注意,迭代器本质就是把底层细节封装起来,让用户像用string和vector原生指针方便的访问链表的各个节点,用户并不需要关心底层到底是怎么实现的,即他是怎么找到下一个节点,只需要像用+±-这种操作完成这个访问数据即可。
  • 总结:迭代器类,实质上就是对list进行+±-和访问运算符*这些和原生指针一样的操作的运算符重载,能够让用户感觉就是在用原生指针一样。

迭代器模版参数的说明

这里我们所实现的迭代器类的模板参数列表当中为什么有三个模板参数?

template<class T, class Ref, class Ptr>
  • 为了和库里面保持一致,我们不光要实现普通list对象的迭代器,还要实现const的list对象的迭代器,其实const的list对象的迭代器和普通list迭代器就是返回的类型不一致,实现上是一致的,这时候我们就可以通过模板自动推导类型来解决。
    在这里插入图片描述

构造函数

list_iterator(Node* node):_node(node)
{}
  • 很简单,我们需要知道从node节点开始迭代访问,那么提供node这个节点

++运算符重载

Self& operator++()
{_node = _node->_next;return *this;
}
  • 从链表节点的类中我们知道节点的下一个节点的位置是用一个_next成员变量指针指向的,所以指向那个位置就行了。

这就是一个后置++的实现,接下来我们实现前置++

	Self operator++(int){Self tmp(*this);_node = _node->_next;return tmp;}
  • 这里我们就是返回自增之前的那个对象
  • 解释下Self的类型,其实就是迭代器对象的类型
typedef list_iterator<T, Ref, Ptr> Self;

- -运算符的重载

		Self& operator--(){_node = _node->_prev;return *this;}
  • 和++相反,++是找到后面的那个节点,而–就是找到前面那个节点。
		Self operator--(int){Self tmp(*this);_node = _node->_prev;return tmp;}
  • 前置- - 同上面前置++

==运算符重载

bool operagor == (const Self & s)
{return _node == s._node;
}
  • 判断两个节点指针指向的地址是否相同即可

!=运算符的重载

  • !=运算符刚好和==运算符的作用相反,我们判断这两个迭代器当中的结点指针的指向是否不同即可
	bool operator!=(const Self& s){return _node != s._node;}

*运算符的重载

		Ref operator*(){return _node->_data;}
  • 返回节点指针的存储数据的成员变量_data就可以了
  • 这里的Ref是引用的类型,模板推导出来的引用类型

->运算符的重载

		Ptr operator->(){return &_node->_data;}
  • 很多同学都不知道重载这个运算符用来干啥,
  • 在这里插入图片描述

在这里插入图片描述

  • 可以看到,当我们链表存储的类型是一个类类型的时候,我们的流插入运算符就不能输出类类型的数据了。这时候我们要么重载留插入运算符,要么就另寻其他办法。

这时候我们观察到,链表节点是一个类,想访问里面的成员变量,可以通过对成员变量的地址->来访问类里面的成员变量。这时候我们就需要这个成员变量的地址对他解引用来访问他。

  • 这时候有的同学就可能会有疑问,那->获取地址后不应该再次->才能得到数据吗,为什么只需要写一个->,这是因为要提升程序的可读性
    例如日期类的成员访问:
    在这里插入图片描述

迭代器相关函数

	iterator begin(){return iterator(_head->_next);}iterator end(){return iterator(_head);}const_iterator begin() const{return const_iterator(_head->_next);}const_iterator end() const{return const_iterator(_head);}
  • 这里只需要把节点传给我们的迭代器类构造一个迭代器对象就可以获得头节点和尾部的迭代器。

插入和删除函数

insert

iterator insert(iterator pos, const T& val)
{Node* cur = pos._node;Node* prev = cur->_prev;Node* newnode = new Node(val);newnode->_next = cur;newnode->_prev = prev;prev->_next = newnode;cur->_prev = newnode;_size++;return iterator(newnode);}
  • 这里插入很easy,只需要把插入的新节点前后指针更新到对应的指针就行了。
    在这里插入图片描述
  • 注意这里插入不存在迭代器失效的问题,因为我们的扩容都是一个个独立的空间,不存在像vector那样扩容后会导致迭代器无法找到新开的空间,这里的迭代器是通过指针来找到空间的

erase函数

	iterator erase(iterator pos){assert(pos != end()); //注意这里是给end, pos是迭代器的类型对象Node* cur = pos._node;Node* prev = cur->_prev;Node* next = cur->_next;next->_prev = prev;prev->_next = next;delete cur;_size--;return iterator(next);}

在这里插入图片描述

  • 这里释放节点就要注意迭代器失效的问题了,我们删除后,指向这个节点的迭代器指向的就是一个无效的内存,这时候就需要更新这个迭代器让他指向有效的内存。
    在这里插入图片描述

在这里插入图片描述

push_fron, pop_back, pop_front

void push_front(const T& x)
{insert(begin(), x);}
void pop_front()
{erase(begin());
}
void pop_back()
{erase(--end());
}
  • 复用insert和erase接口就行,push_front就是insert到头结点位置,pop_front就是删除头结点位置,pop_back则是删除end(end是最后一个节点的下一个节点)前一个位置

其他函数

size函数

size_t size() const
{return _size;
}
  • 我们通过,一个成员变量来实现,如果链表插入节点的时候就自增_size,删除节点的时候就自减_size,可以看看前面的插入和删除函数

clear函数

	void clear(){auto it = begin();while (it != end()){it = erase(it);}}
  • 析构函数哪里前面已经解释过

swap函数

		void swap(list<T>& tmp){std::swap(_head, tmp._head);}
  • 这里ist容器当中存储的实际上就只有链表的头指针,我们就交换两个变量的头结点就行了,就让他们交换了数据,
  • 这里我们还重载了一个全局的swap函数
template<class T>
void swap(list<T>& a, list<T>& b)
{a.swap(b);
}
  • 这一点我在string和vector中也说过
  • 为了防止使用算法库中的i那个很多拷贝构造的swap函数,我们重载一个全局函数通过模板有现成吃现成(两个链表类型的变量,相同的类型),会优先匹配我们自己实现的swap函数,然后我们这个全局的函数又调用成员函数swap,这个效率比算法库的那个效率高很多,为啥效率高,请看前面两个容器的讲解很详细。

list的sort vs 库的sort

List为啥要自己实现一个sort函数来排序,不能直接用算法库中的sort吗?
1.不能,因为我们的迭代器按功能角度来分类有3种:
(1)单向迭代器(支持++) 例如:foward_list(单链表)
(2)双向迭代器(支持++.–), list
(3)随机迭代器(支持++,–, +, -) string,vector
在这里插入图片描述
在这里插入图片描述

vector和list的排序效率

在这里插入图片描述

  • 我们第一组数据是vector用算法库sort和list用他的成员函数sort单独排序,第二组数据是list的数据拷贝到vector给算法库的sort排序和list用他的成员函数sort单独排序
  • 可以看到copy到vector给算法库的sort排序都比list的sort快

原因:
1链表这个不连续的结构并不适合大量数据的排序,他的索引访问不能像vector那样连续的索引访问那么高效,需要更多时间来找到索引位置
2.算法库中的sort是快速排序算法,list的sort用的是归并排序,快速排序还是比归并排序要厉害一点的。

  • ,想要更高的效率排序,最好拷贝到vector中排序,排完再拷贝回list

从迭代器类重新理解封装

  • 大家可以看到我们的迭代器类实际上是一个
	struct list_iterator
  • 在类外是可以访问的,虽然在类外是可以访问,但是我们通过对迭代器类重命名
	typedef list_iterator<T, T&, T*> iterator;typedef list_iterator<T, const T&, const T*> const_iterator;
  • 提供了类外统一用iterator来访问的方式,这样外面并不知道我实际是什么名字,并不能很好的猜出来,可以看到我们stl中容器的迭代器都是统一命名为iterator, 但是每个容器的迭代器的底层细节实现方式可能都有差异,但是用户都可以通过iterator来访问各个容器,只能通过我给的接口访问,这就是一个隐式的封装
  • 为啥要写成struct,就是为了方便类里面对他的高频访问的问题。如迭代器函数begin,插入insert
    在这里插入图片描述

end

感谢大家阅读,希望对大家有帮助,快去实现一下吧

相关文章:

【C++】list底层封装和实现

目录 节点类基本框架构造函数 list类构造函数拷贝构造函数赋值重载析构函数 迭代器类前言(string和vector的区别)迭代器模版参数的说明构造函数运算符重载- -运算符的重载运算符重载!运算符的重载*运算符的重载->运算符的重载 迭代器相关函数插入和删除函数inserterase函数p…...

一种替代DOORS在WORD中进行需求管理的方法 (二)

一、前景 参考&#xff1a; 一种替代DOORS在WORD中进行需求管理的方法&#xff08;基于WORD插件的应用&#xff09;_doors aspice-CSDN博客 二、界面和资源 WORD2013/WORD2016 插件 【已使用该工具通过第三方功能安全产品认证】&#xff1a; 1、 核心功能 1、需求编号和跟…...

学习海康VisionMaster之多直线查找

一&#xff1a;进一步学习了 今天学习下VisionMaster中的多直线查找&#xff0c;这个还是拟合直线的衍生应用&#xff0c;可以在测量框内同时查找多段时间 二&#xff1a;开始学习 1&#xff1a;什么是多直线查找&#xff1f; 一个检测框&#xff0c;就可以在检测框里面同时检…...

MATLAB的24脉波整流器Simulink仿真与故障诊断

本博客来源于CSDN机器鱼&#xff0c;未同意任何人转载。 更多内容&#xff0c;欢迎点击本专栏目录&#xff0c;查看更多内容。 目录 0 引言 1 故障数据采集 2 故障特征提取 3 故障诊断分类 4 结语 本博客内容是在MATLAB2023下完成。 0 引言 对于电力电子电路的故障诊断…...

顺序表专题(C语言)

文章目录 前言一、数据结构相关概念类比说明&#xff1a;书架与数据结构 二、线性表基本概念两种实现方式对比 三、顺序表的概念及结构1. 顺序表的定义2. 静态顺序表的基本结构关键点解析&#xff1a; 3. 结构体成员解释 四、顺序表分类五、动态顺序表的实现总结 前言 在C语言…...

Python Cookbook-5.9 在排序完毕的序列中寻找元素

任务 你需要寻找序列中的一系列元素。 解决方案 解决方案如果列表L已经是排序完毕的状态&#xff0c;则Python 标准库提供的 bisect 模块可以很容易地检查出元素x是否在L中: import bisect x_insert_point bisect.bisect_right(L,x) x_is_present L[x_insert_point-1:x_i…...

Johnson算法 流水线问题 java实现

某印刷厂有 6项加工任务J1&#xff0c;J2&#xff0c;J3&#xff0c;J4&#xff0c;J5&#xff0c;J6&#xff0c;需要在两台机器Mi和M2上完 成。 在机器Mi上各任务所需时间为5,1,8,5,3,4单位; 在机器M2上各任务所需时间为7,2,2,4,7,4单位。 即时间矩阵为&#xff1a; T1 {5, …...

10:00开始面试,10:08就出来了,问的问题有点变态。。。

从小厂出来&#xff0c;没想到在另一家公司又寄了。 到这家公司开始上班&#xff0c;加班是每天必不可少的&#xff0c;看在钱给的比较多的份上&#xff0c;就不太计较了。没想到8月一纸通知&#xff0c;所有人不准加班&#xff0c;加班费不仅没有了&#xff0c;薪资还要降40%…...

[Vue]App.vue讲解

页面中可以看见的内容不再在index.html中进行编辑&#xff0c;而是在App.vue中进行编辑。 组件化开发 在传统的html开发中&#xff0c;一个页面的资源往往都写在同一个html文件中。这种模式在开发小规模、样式简单的项目时会相当便捷&#xff0c;但当项目规模越来越大&#xf…...

python中的*args和**args

在 Python 里&#xff0c;*args 和 **kwargs 是两个特殊的语法&#xff0c;它们能让函数接收不定数量的参数。下面分别对它们进行介绍。 *args *args 用于向函数传递不定数量的非关键字参数&#xff0c;这些参数会被封装成一个元组。以下是示例代码&#xff1a; def sum_num…...

解决Spring Boot上传默认限制文件大小和完善超限异常(若依框架)

文章目录 报错信息问题分析技术原理解决方法1️⃣调整 Spring Boot 配置文件2️⃣检查内嵌 Tomcat 配置&#xff08;可选&#xff09;3️⃣ 代码自定义配置&#xff08;覆盖配置文件&#xff09; 全局异常处理代码 报错信息 org.springframework.web.multipart.MaxUploadSizeE…...

Pyside6使用QtWebEngine实现GUI嵌入网页内容

Pyside6是由Qt官方维护和开发的一个用于创建跨平台桌面应用程序的Python绑定库。QtWebEngine是Qt提供的一个模块&#xff0c;它基于Chromium项目&#xff0c;允许开发者在他们的应用程序中嵌入网页内容。通过结合Pyside6和QtWebEngine&#xff0c;开发者可以轻松地创建具有现代…...

【每日一个知识点】多项式回归(Polynomial Regression)

多项式回归&#xff08;Polynomial Regression&#xff09;是一种对非线性关系建模的回归方法&#xff0c;它是在线性回归的基础上&#xff0c;引入特征的高次项&#xff0c;从而捕捉自变量与因变量之间的非线性关系。 &#x1f539;一、基本概念 多项式回归的形式&#xff1a…...

最新版PhpStorm超详细图文安装教程,带补丁包(2025最新版保姆级教程)

目录 前言 一、PhpStorm最新版下载 二、PhpStorm安装 三、PhpStorm补丁 四、运行PhpStorm 前言 PhpStorm 是 JetBrains 公司推出的 专业 PHP 集成开发环境&#xff08;IDE&#xff09;&#xff0c;专为提升 PHP 开发效率设计。其核心功能包括智能代码补全、实时语法错误检…...

C++:模拟实现string

目录 一&#xff1a;string类 二&#xff1a;构造函数、拷贝构造函数及析构函数 1、构造函数 2、拷贝构造函数 3、析构函数 三、实现string中对容量操作的成员函数 1、size 2、capacity 3、reserve 4、resize 5、clear 6、empty 四、string类中对象的增删查改操作 …...

Python 小练习系列 | Vol.14:掌握偏函数 partial,用函数更丝滑!

&#x1f9e9; Python 小练习系列 | Vol.14&#xff1a;掌握偏函数 partial&#xff0c;用函数更丝滑&#xff01; 本节的 Python 小练习系列我们将聚焦一个 冷门但高能 的工具 —— functools.partial。它的作用类似于“函数的预设模板”&#xff0c;能帮你写出更加灵活、优雅…...

处理Excel的python库openpyxl、xlrd、xlwt、pandas有什么区别,搞懂它

openpyxl、xlrd、xlwt、pandas 都能处理 Excel 表格&#xff0c;但用途和适合的场景不同。今天做个总结&#xff1a; 库名功能支持格式读写支持样式备注openpyxl全面的.xlsx处理库.xlsx&#xff08;Excel2007&#xff09;✅✅✅首选xlrd读取.xls文件的老牌工具.xls&#xff08…...

【OSG学习笔记】Day 1: OSG初探——环境搭建与第一个3D窗口

什么是 OSG&#xff1f; 全称&#xff1a;OpenSceneGraph&#xff08;开源场景图&#xff09; 定位&#xff1a;一个基于 C/OpenGL 的高性能开源3D图形开发工具包&#xff0c;专注于实时渲染和复杂场景管理。 核心思想&#xff1a;通过 场景图&#xff08;Scene Graph&#xf…...

linux--------------进程控制(下)

一、进程等待 1.1 进程等待必要性 子进程退出后&#xff0c;若父进程不管不顾&#xff0c;可能会产生 “僵尸进程”&#xff0c;进而造成内存泄漏。进程一旦变为僵尸状态&#xff0c;即使使用 kill -9 也无法将其杀死&#xff0c;因为无法杀死一个已死的进程。父进程需要了解…...

【Axure元件分享】移动端滑动拨盘日期选择器

在移动端产品设计中&#xff0c;日期选择器是用户交互中常见的组件&#xff0c;尤其在预订、日程管理等场景中扮演着关键角色。本文将介绍一款基于Axure的移动端滑动拨盘日期选择器元件&#xff0c;该元件通过模拟拨盘滑动交互效果&#xff0c;为用户提供直观日期选择体验。 下…...

基于 JavaWeb 的 SpringBoot 在线课程会员系统设计和实现(源码+文档+部署讲解)

技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;免费功能设计、开题报告、任务书、中期检查PPT、系统功能实现、代码编写、论文编写和辅导、论文…...

Linux入门

复习:https://blog.csdn.net/ 操作系统概述 硬件和软件 计算机由硬件和软件组成 硬件:计算机系统中由电子,机械和光电元件等组成的各种物理装置的总称 软件:用户和计算机硬件之间的接口和桥梁,用户通过软件与计算机进行交流 而操作系统就是软件的一类. 操作系统 主要负…...

金融壹账通推出大模型一体机,加速金融行业AI落地与应用

在当前数字化和人工智能技术迅猛发展的背景下,金融行业正面临着效率提升、风险管控和客户体验优化的多重挑战。为应对这些需求,金融壹账通近期推出了全新的“大模型一体机”解决方案。该方案集算力、模型、工具链和应用场景于一体,不仅具备小投入、低门槛和私有化部署的优势,还…...

迁移WordPress网站(大文件版本)

安装插件All-in-One WP Migration&#xff0c;备份并下载文件&#xff0c;可以参考我的另外一篇文章wordpress 利用 All-in-One WP Migration全站转移使用工具解压缩.wpress文件 工具名称&#xff1a;wpress-extractor&#xff0c;github下载地址 或者 我已经上传&#xff0c;也…...

Linux普通用户怎么切换为root用户

在 Linux 中&#xff0c;普通用户切换到 root 用户的常用命令有以下几种&#xff1a; 切到root用户 sudo -i&#xff08;当前用户的密码&#xff09; su -&#xff08;需要知道root 密码&#xff09; 1. su 命令&#xff08;需要知道 root 密码&#xff09; su - 或 su - roo…...

WinForm真入门(11)——ComboBox控件详解

WinForm中 ComboBox 控件详解‌ ComboBox 是 WinForms 中一个集文本框与下拉列表于一体的控件&#xff0c;支持用户从预定义选项中选择或直接输入内容。以下从核心属性、事件、使用场景到高级技巧的全面解析&#xff1a; 一、ComboBox 核心属性‌ 属性说明示例‌Items‌下拉…...

Spring 服务调用接口时,提示You should be redirected automatically to target URL:

问题 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><title>Redirecting...</title><h1>Redirecting...</h1><p>You should be redirected automatically to target URL: <a href"http://xxx/api/v1/branch…...

OpenCV--模板匹配

一、引言 在计算机视觉领域&#xff0c;模板匹配是一种用于在图像中查找特定目标的基本技术。OpenCV 作为广泛使用的计算机视觉库&#xff0c;提供了强大且易于使用的模板匹配功能。无论是在工业检测、图像识别还是机器人视觉等领域&#xff0c;模板匹配都发挥着重要作用。本文…...

【Ragflow】14.MinerU解析脚本,接入ragflow知识库

概述 前文写了下 MinerU 的解析效果&#xff0c;收到不少读者催更&#xff0c;想利用 MinerU 替换 Deepdoc 的原始的解析器。 我认为&#xff0c;开发新功能基本可遵循能用-好用-用好这三个阶段&#xff1a; 能用&#xff1a;先通过脚本实现该功能,主打的是能用就行 好用&am…...

【SpringCloud】从入门到精通(上)

今天主播我把黑马新版微服务课程MQ高级之前的内容都看完了&#xff0c;虽然在看视频的时候也记了笔记&#xff0c;但是看完之后还是忘得差不多了&#xff0c;所以打算写一篇博客再温习一下内容。 课程坐标:黑马程序员SpringCloud微服务开发与实战 微服务 认识单体架构 单体架…...

第一章:SQL 基础语法与数据查询

1. 什么是 SQL&#xff1f;​​ ​​SQL&#xff08;Structured Query Language&#xff09;​​ 是用于管理和操作关系型数据库的标准语言。核心功能&#xff1a; ​​数据查询​​&#xff08;SELECT&#xff09;​​数据定义​​&#xff08;CREATE、ALTER、DROP&#xff0…...

Openlayers:海量图形渲染之WebGL渲染

最近由于在工作中涉及到了海量图形渲染的问题&#xff0c;因此我开始研究相关的解决方案。我在网络上寻找相关的解决方案时发现许多的文章都提到利用Openlayers中的WebGLPointsLayer类&#xff0c;可以实现渲染海量的点&#xff0c;之后我又了解到利用WebGLVectorLayer类可以渲…...

任务调度和安全如何结合

联邦学习与隐私保护 分布式模型训练&#xff1a;各边缘节点本地训练调度模型&#xff0c;仅共享模型参数而非原始数据&#xff0c;避免隐私泄露&#xff08;参考[11]的联邦学习框架&#xff09;。差分隐私&#xff1a;在奖励计算或状态反馈中加入噪声&#xff0c;防止通过调度…...

ARP攻击 DAI动态ARP检测学习笔记(超详细)

一、概述 ARP(Address Resolution Protocol,地址解析协议)是将IP地址解析为以太网MAC地址(或称为物理地址)的协议,指导三层报文的转发。ARP有简单、易用的优点,但是也因为其没有任何安全认证机制而容易被攻击者利用。属于是又爱又恨的一种协议了。目前ARP攻击和ARP病毒已经成为…...

Springboot--Kafka客户端参数关键参数的调整方法

调整 Kafka 客户端参数需结合生产者、消费者和 Broker 的配置&#xff0c;以实现性能优化、可靠性保障或资源限制。以下是关键参数的调整方法和注意事项&#xff1a; 一、生产者参数调整 ‌max.request.size‌ ‌作用‌&#xff1a;限制单个请求的最大字节数&#xff08;包括消…...

NO.79十六届蓝桥杯备战|数据结构-扩展域并查集-带权并查集|团伙|食物链|银河英雄传说(C++)

扩展域并查集 普通的并查集只能解决各元素之间仅存在⼀种相互关系&#xff0c;⽐如《亲戚》题⽬中&#xff1a; a 和b 是亲戚关系&#xff0c;b 和c 是亲戚关系&#xff0c;这时就可以查找出a 和c 也存在亲戚关系。 但如果存在各元素之间存在多种相互关系&#xff0c;普通并查…...

蓝桥杯2022年第十三届省赛真题-统计子矩阵

题目链接&#xff1a; 代码思路&#xff1a; ①枚举上、下边界。 ②求每一列前缀和。 ②固定上下边界后&#xff0c;在通过双指针确定子矩阵的左右边界。双指针维护一个窗口 [l, r]&#xff0c;确保窗口中所有列的和(下面前缀和-上面前缀和)不超过 K。通过滑动窗口方式&…...

openEuler24.03 LTS下安装Spark

目录 安装模式介绍 下载Spark 安装Local模式 前提条件 解压安装包 简单使用 安装Standalone模式 前提条件 集群规划 解压安装包 配置Spark 配置Spark-env.sh 配置workers 分发到其他机器 启动集群 简单使用 关闭集群 安装YARN模式 前提条件 解压安装包 配…...

openEuler24.03 LTS下安装Flink

目录 Flink的安装模式下载Flink安装Local模式前提条件解压安装包启动集群查看进程提交作业文件WordCount持续流WordCount 查看Web UI配置flink-conf.yaml简单使用 关闭集群 Standalone Session模式前提条件Flink集群规划解压安装包配置flink配置flink-conf.yaml配置workers配置…...

Redis 持久化

一、持久化 redis 虽然是个内存数据库&#xff0c;但是 redis 支持RDB 和 AOF 两种持久化机制&#xff0c; 将数据写往磁盘&#xff0c;可以有效的避免因进程退出造成的数据丢失问题&#xff0c;当下次重启时利用之前持久化的文件即可实现数据恢复。 二、Redis 支持RDB 和 AOF …...

塔能科技:智能路灯物联运维产业发展现状与趋势分析

随着智慧城市建设的推进&#xff0c;智能路灯物联运维产业正经历快速发展&#xff0c;市场规模持续扩大。文章探讨了智能路灯物联运维的技术体系、市场机遇和挑战&#xff0c;并预测了未来发展趋势&#xff0c;为行业发展提供参考。 关键词 智能路灯&#xff1b;物联运维&#…...

前端知识点---闭包(javascript)

文章目录 1.怎么理解闭包?2.闭包的特点3.闭包的作用?4 闭包注意事项&#xff1a;5 形象理解 1.怎么理解闭包? 函数里面包着另一个函数&#xff0c;并且内部函数可以访问外部函数的变量。 <script>function outer(){let count 0return functioninner (){countconsole.l…...

单次 CMS Old GC 耗时长问题分析与优化

目录 一、现象说明 二、CMS GC 机制简述 三、可能导致长时间停顿的原因详细分析 &#xff08;一&#xff09;Full GC&#xff08;完全垃圾回收&#xff09; 1. 主要原因 2.参数调整 &#xff08;二&#xff09;Promotion Failure&#xff08;晋升失败&#xff09; 1. 主…...

Python星球日记 - 第16天:爬虫基础(仅学习使用)

&#x1f31f;引言&#xff1a; 上一篇&#xff1a;Python星球日记 - 第15天&#xff1a;综合复习&#xff08;回顾前14天所学知识&#xff09; 名人说&#xff1a;不要人夸颜色好&#xff0c;只留清气满乾坤&#xff08;王冕《墨梅》&#xff09; 创作者&#xff1a;Code_流苏…...

【回眸】Linux 内核 (十四)进程间通讯 之 信号量

前言 信号量概念 信号量常用API 1.创建/获取一个信号量 2.改变信号量的值 3. 控制信号量 信号量函数调用 运行结果展示 前言 上一篇文章介绍的共享内存有局限性,如:同步与互斥问题、内存管理复杂性问题、数据结构限制问题、可移植性差问题、调试困难问题。本篇博文介…...

Python 字典和集合(字典的变种)

本章内容的大纲如下&#xff1a; 常见的字典方法 如何处理查找不到的键 标准库中 dict 类型的变种set 和 frozenset 类型 散列表的工作原理 散列表带来的潜在影响&#xff08;什么样的数据类型可作为键、不可预知的 顺序&#xff0c;等等&#xff09; 字典的变种 这一节总结了…...

LeetCode】寻找重复子树:深度解析与高效解法

&#x1f4d6; 问题描述 给定一棵二叉树的根节点 root &#xff0c;返回所有重复的子树。若两棵树结构相同且节点值相同&#xff0c;则认为它们是重复的。对于同类重复子树&#xff0c;只需返回其中任意一棵的根节点。 &#x1f330; 示例解析 示例1 输入&#xff1a; 1/ …...

[蓝桥杯] 挖矿(CC++双语版)

题目链接 P10904 [蓝桥杯 2024 省 C] 挖矿 - 洛谷 题目理解 我们可以将这道题中矿洞的位置理解成为一个坐标轴&#xff0c;以题目样例绘出坐标轴&#xff1a; 样例&#xff1a; 输入的5为矿洞数量&#xff0c;4为可走的步数。第二行输入是5个矿洞的坐标。输出结果为在要求步数…...

Appium如何实现移动端UI自动化测试?

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 Appium是一个开源跨平台移动应用自动化测试框架。 既然只是想学习下Appium如何入门&#xff0c;那么我们就直奔主题。文章结构如下&#xff1a; 为什么要使用A…...

在集合中哪些可以为null,哪些不能为null;Java 集合中 null 值允许情况总结与记忆技巧

Java 集合中 null 值允许情况总结与记忆技巧 一、核心集合对 null 的支持情况 集合类型Key 是否可为 nullValue 是否可为 null原因/备注HashMap✅ 是✅ 是对 null key 有特殊处理&#xff08;存放在数组第 0 个位置&#xff09;LinkedHashMap✅ 是✅ 是继承自 HashMapTreeMap…...