C++:List的使用和模拟实现

✨✨✨学习的道路很枯燥,希望我们能并肩走下来!

文章目录

目录

文章目录

前言

一 list的介绍及使用

1.1 list的介绍

1.2 list的使用 

1.2.1 list的构造

1.2.2 list iterator的使用

1.2.3 list capacity 

1.2.4 list element access 

 1.2.5 list modifiers

1.2.6 list的迭代器失效 

 1.2.7 List中sort的效率测试

二、list的模拟实现

 2.1 正向迭代器的实现

2.1.1 正向迭代器的封装 

 2.1.2 迭代器的使用

2.2 list相关的成员函数

 2.2.1 构造函数

2.2.1.1 默认构造函数

 2.2.1.2 有参构造函数

 2.2.1.3 迭代器区间构造函数 

2.2.1.4 拷贝构造 

1.传统 

2.现代 

2.2.2 析构函数和clear

2.2.2.1 析构函数

2.2.2.2 clear()

 2.2.3 赋值重载

2.2.4.1 empty、size

 2.2.4.2 insert

2.2.4.3 erase 

2.2.4.4 尾插尾删头插头删 

2.3 反向迭代器的实现 

 

三 list模拟实现的全部代码


前言

本篇详细介绍了list的使用和模拟实现,让使用者了解list,而不是仅仅停留在表面,更好的模拟,为了更好的使用. 文章可能出现错误,如有请在评论区指正,让我们一起交流,共同进步!


一 list的介绍及使用

1.1 list的介绍

list文本介绍

1. list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代

2. list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。

3. list与forward_list非常相似:最主要的不同在于forward_list是单链表,只能朝前迭代,已让其更简单高效。

4. 与其他的序列式容器相比(array,vector,deque),list通常在任意位置进行插入、移除元素的执行效率更好。

5. 与其他序列式容器相比,list和forward_list最大的缺陷是不支持任意位置的随机访问,比如:要访问list 的第6个元素,必须从已知的位置(比如头部或者尾部)迭代到该位置,在这段位置上迭代需要线性的时间开销;list还需要一些额外的空间,以保存每个节点的相关联信息(对于存储类型较小元素的大list来说这可能是一个重要的因素)

1.2 list的使用 

list中的接口比较多,此处类似,只需要掌握如何正确的使用,然后再去深入研究背后的原理,已达到可扩展 的能力。以下为list中一些常见的重要接口。

1.2.1 list的构造

构造函数( (constructor))接口说明
list (size_type n, const value_type& val = value_type())构造的list中包含n个值为val的元素
list()构造空的list
list (const list& x)拷贝构造函数
list (InputIterator first, InputIterator last)用[first, last)区间中的元素构造list

1.2.2 list iterator的使用

此处,大家可暂时将迭代器理解成一个指针,该指针指向list中的某个节点

函数声明接口说明
begin + end返回第一个元素的迭代器+返回最后一个元素下一个位置的迭代器
rbegin + rend返回第一个元素的reverse_iterator,即end位置,返回最后一个元素下一个位置的 reverse_iterator,即begin位置

【注意】

1. begin与end为正向迭代器,对迭代器执行++操作,迭代器向后移动

2. rbegin(end)与rend(begin)为反向迭代器,对迭代器执行++操作,迭代器向前移动 

1.2.3 list capacity 

函数声明接口说明
empty检测list是否为空,是返回true,否则返回false
size返回list中有效节点的个数

1.2.4 list element access 

函数声明接口说明
front返回list的第一个节点中值的引用
back返回list的最后一个节点中值的引用

 1.2.5 list modifiers

函数声明接口说明
push_front在list首元素前插入值为val的元素
pop_front删除list中第一个元素
push_back在list尾部插入值为val的元素
pop_back删除list中最后一个元素
insert在list position 位置中插入值为val的元素
erase删除list position位置的元素
swap交换两个list中的元素
clear清空list中的有效元素

list中还有一些操作,需要用到时大家可参阅list的文档说明。

1.2.6 list的迭代器失效 

前面说过,此处大家可将迭代器暂时理解成类似于指针

迭代器失效即迭代器所指向的节点的无效,即该节点被删除了。

因为list的底层结构为带头结点的双向循环链表,因此在list中进行插入时是不会导致list的迭代器失效的,只有在删除时才会失效,并且失效的只是指向被删除节点的迭代器,其他迭代器不会受到影响。

void TestListIterator1(){int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };list<int> l(array, array+sizeof(array)/sizeof(array[0]));auto it = l.begin();while (it != l.end()){// erase()函数执行后,it所指向的节点已被删除,因此it无效,在下一次使用it时,必须先给
其赋值l.erase(it);  ++it;}}// 改正
void TestListIterator(){int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };list<int> l(array, array+sizeof(array)/sizeof(array[0]));auto it = l.begin();while (it != l.end()){l.erase(it++);    }}

 1.2.7 List中sort的效率测试

我们用一段代码来测试一下list中sort的性能

#include<iostream>
#include<algorithm>
#include<vector>
#include<list>
using namespace std;
void test_op()
{srand((unsigned int)time(NULL));const int N = 1000000;vector<int> v;v.reserve(N);list<int> lt1;list<int> lt2;for (int i = 0; i < N; ++i){int e = rand();lt1.push_back(e);lt2.push_back(e);}// 拷贝到vector排序,排完以后再拷贝回来int begin1 = clock();for (auto e : lt1){v.push_back(e);}sort(v.begin(), v.end());size_t i = 0;for (auto& e : lt1){e = v[i++];}int end1 = clock();//list调用自己的sortint begin2 = clock();lt2.sort();int end2 = clock();printf("vector sort:%d\n", end1 - begin1);printf("list sort:%d\n", end2 - begin2);
}

 

会发现哪怕我先拷贝到vector排完再拷贝回去效率都比list的sort效率高,所以list的sort实际中意义不是很大!! 

二、list的模拟实现

 2.1 正向迭代器的实现

2.1.1 正向迭代器的封装 

我们在学习vector的时候,发现vector的迭代器就是一个原生指针T*,这得益于vector的空间的连续性

那我们还能像vector一样用原生指针去修饰迭代器吗?

不能,链表空间上是不连续的,那我们对一个节点指针进行加减,就很难说能不能找到下一个节点,更多的是找不到的情况

我们在数据结构中访问下一个节点,往往是利用当前节点存的下一节点的地址来进行访问的

所以我们可以将迭代器单独封装成一个类去管理节点

template<class T, class Ref, class Ptr> //Ref == T& Ptr == T*
struct ListIterator //这里使用struct是因为我们要多次访问成员,也可使用class+public
{typedef ListNode<T>* PNode;typedef ListIterator<T, Ref, Ptr> Self;ListIterator(PNode pNode = nullptr) :_pNode(pNode){}ListIterator(const Self& l) :_pNode(l._pNode){}T& operator*() //解引用{return _pNode->_val;}T* operator->() {return &_pNode->_val;}Self& operator++() //前置++{_pNode = _pNode->_pNext;return *this;}Self operator++(int) //后置++{Self temp(*this);_pNode = _pNode->_pNext;return temp;}Self& operator--() //前置--{_pNode = _pNode->_pPre;return *this;}Self& operator--(int) //后置--{Self temp(*this);_pNode = _pNode->_pPre;return temp;}bool operator!=(const Self& l) //不相等判断{return _pNode != l._pNode;}bool operator==(const Self& l) //相等判断{return !(*this != l);}PNode _pNode;
};

 T* operator->()  大家可能有疑惑

 当我们的节点里存的是内置类型或者STL容器是,库里面的<<重载了这些来读取数据

但如果是我们自己写的类型(如class CH),<<并不能读取该类型的数据

因此我们要取来节点自定义类的指针,来访问该类的内部的数据(因为最底层都是内置类型

 2.1.2 迭代器的使用

 template<class T>class list{typedef ListNode<T> Node;typedef Node* PNode;public:typedef ListIterator<T, T&, T*> iterator;typedef ListIterator<T, const T&, const T&> const_iterator;public:iterator begin(){return iterator(_pHead->_pNext);}iterator end(){return iterator(_pHead);}const_iterator begin()const{return const_iterator(_pHead->_pNext);}const_iterator end()const{return const_iterator(_pHead);}
private:PNode _pHead;    
}

这边我们用到了匿名对象。 

这里的const迭代器为什么不能直接用const修饰普通迭代器??

 因为typedef碰到const的话,就不是简单的字符串替换  实际上你以为的const T* ,在这里变成了T*const ,因为迭代器我们是希望他可以进行++和--的,而我们只是不希望他指向的内容给改变,所以我们的const要修饰的是指针的内容,而不是修饰指针。

2.2 list相关的成员函数

 2.2.1 构造函数

2.2.1.1 默认构造函数
list()
{_pHead = new Node;_pHead->_pPre = _pHead;_pHead->_pNext = _pHead;
}    

因为无论如何都要有哨兵节点(方便我们不用判空,所以我们直接封装一个 

void CreateHead()
{_pHead = new Node;_pHead->_pPre = _pHead;_pHead->_pNext = _pHead;
}
 2.2.1.2 有参构造函数
 list(int n, const T& value = T()){CreateHead();for (int i = 0; i < n; ++i)push_back(value);}
 2.2.1.3 迭代器区间构造函数 
template <class Iterator>
list(Iterator first, Iterator last)
{CreateHead();while (first != last){push_back(*first);++first;}
}
2.2.1.4 拷贝构造 
1.传统 
//拷贝构造函数传统写法
list(const list<T>& l)
{CreateHead();for (auto e : l)push_back(e);
}
2.现代 
void swap(list<T>& l)
{std::swap(_pHead, l._pHead);
}list(const list<T>& l)
{CreateHead();// 用l中的元素构造临时的temp,然后与当前对象交换list<T> temp(l.begin(), l.end());swap(temp);
}

2.2.2 析构函数和clear

2.2.2.1 析构函数
~list()
{clear();delete _pHead;_pHead = nullptr;
}
2.2.2.2 clear()
void clear()
{iterator p = begin();while (p != end()){p = erase(p);}_pHead->_pPre = _pHead;_pHead->_pNext = _pHead;
}

 2.2.3 赋值重载

list<T>& operator=(const list<T> l)
{swap(l);return *this;
}

2.2.4 修改相关函数(Modifiers)

2.2.4.1 empty、size
size_t size()const
{size_t size = 0;ListNode* p = _pHead->_pNext;while (p != _pHead){size++;p = p->_pNext;}return size;
}
bool empty()const
{return size() == 0;
}
 2.2.4.2 insert
// 在pos位置前插入值为val的节点
iterator insert(iterator pos, const T& val)
{PNode newnode = new Node(val);PNode cur = pos._pNode;PNode prev = cur->_pPre;newnode->_pPre = prev;newnode->_pNext = cur;prev->_pNext = newnode;cur->_pPre = newnode;return iterator(newnode);
}
2.2.4.3 erase 
// 删除pos位置的节点,返回该节点的下一个位置
iterator erase(iterator pos)
{assert(pos != end());PNode prev = pos._pNode->_pPre;PNode next = pos._pNode->_pNext;prev->_pNext = next;next->_pPre = prev;delete pos._pNode;return iterator(next);//利用匿名对象返回
}
2.2.4.4 尾插尾删头插头删 
 // List Modifyvoid push_back(const T& val){insert(end(), val);}void pop_back(){erase(--end());}void push_front(const T& val){insert(begin(), val);}void pop_front(){erase(begin());}

2.3 反向迭代器的实现 

 sgi版本下的反向迭代器,其实就是将构建一个反向迭代器的类将正向迭代器封装起来,这个时候正向迭代器的++就是反向迭代器的--

namespace bit
{// 适配器 -- 复用template<class Iterator, class Ref, class Ptr>   //Ref == T&  Ptr == T*struct Reverse_iterator{typedef Reverse_iterator<Iterator, Ref, Ptr> Self;Reverse_iterator(Iterator it):_it(it){}Ref operator*(){Iterator temp = _it;--temp;return *temp;}Self& operator++(){--_it;return *this;}Self operator++(int){Iterator tmp = _it;--_it;return tmp;}Self& operator--(){++_it;return *this;}Self operator--(int){iterator temp = _it;++_it;return temp;}bool operator!=(const Self& s){return _it != s._it;}bool operator==(const Self& s){return _it == s._it;}Iterator _it;};
}

 为什么解引用的是前一个位置的元素???

 

 from C++:List的使用和模拟实现-CSDN博客 图来源

 

三 list模拟实现的全部代码

#pragma once
namespace ch
{// List的节点类template<class T>struct ListNode{ListNode(const T& val = T()) :_pPre(nullptr),_pNext(nullptr),_val(val){}ListNode<T>* _pPre;ListNode<T>* _pNext;T _val;};//List的迭代器类template<class T, class Ref, class Ptr>struct ListIterator{typedef ListNode<T>* PNode;typedef ListIterator<T, Ref, Ptr> Self;ListIterator(PNode pNode = nullptr) :_pNode(pNode){}ListIterator(const Self& l) :_pNode(l._pNode){}T& operator*(){return _pNode->_val;}T* operator->(){return &_pNode->_val;}Self& operator++(){_pNode = _pNode->_pNext;return *this;}Self operator++(int){Self temp(*this);_pNode = _pNode->_pNext;return temp;}Self& operator--(){_pNode = _pNode->_pPre;return *this;}Self& operator--(int){Self temp(*this);_pNode = _pNode->_pPre;return temp;}bool operator!=(const Self& l){return _pNode != l._pNode;}bool operator==(const Self& l){return !(*this != l);}PNode _pNode;};template<class Iterator, class Ref, class Ptr>   //Ref == T&  Ptr == T*struct Reverse_iterator{typedef Reverse_iterator<Iterator, Ref, Ptr> Self;Reverse_iterator(Iterator it):_it(it){}Ref operator*(){Iterator temp = _it;--temp;return *temp;}Self& operator++(){--_it;return *this;}Self operator++(int){Iterator tmp = _it;--_it;return tmp;}Self& operator--(){++_it;return *this;}Self operator--(int){iterator temp = _it;++_it;return temp;}bool operator!=(const Self& s){return _it != s._it;}bool operator==(const Self& s){return _it == s._it;}Iterator _it;};//list类template<class T>class list{typedef ListNode<T> Node;typedef Node* PNode;public://正向迭代器typedef ListIterator<T, T&, T*> iterator;typedef ListIterator<T, const T&, const T&> const_iterator;//反向迭代器typedef Reverse_iterator<iterator, T&, T*>  reverse_iterator;typedef Reverse_iterator<iterator, const T&, const T*>  const_reverse_iterator;public:///// List的构造list(){CreateHead();}list(int n, const T& value = T()){CreateHead();for (int i = 0; i < n; ++i)push_back(value);}template <class Iterator>list(Iterator first, Iterator last){CreateHead();while (first != last){push_back(*first);++first;}}list(const list<T>& l){CreateHead();// 用l中的元素构造临时的temp,然后与当前对象交换list<T> temp(l.begin(), l.end());swap(temp);}list<T>& operator=(const list<T> l){swap(l);return *this;}~list(){clear();delete _pHead;_pHead = nullptr;}///// List Iteratoriterator begin(){return iterator(_pHead->_pNext);}iterator end(){return iterator(_pHead);}const_iterator begin()const{return const_iterator(_pHead->_pNext);}const_iterator end()const{return const_iterator(_pHead);}//反向迭代器(可读可写)reverse_iterator rbegin(){return reverse_iterator(end());}reverse_iterator rend(){return reverse_iterator(begin());}//反向迭代器(可读不可写)const_reverse_iterator rbegin() const{return const_reverse_iterator(end());}const_reverse_iterator rend() const{return const_reverse_iterator(begin());}///// List Capacitysize_t size()const{size_t size = 0;ListNode* p = _pHead->_pNext;while (p != _pHead){size++;p = p->_pNext;}return size;}bool empty()const{return size() == 0;}// List AccessT& front(){assert(!empty());return _pHead->_pNext->_val;}const T& front()const{assert(!empty());return _pHead->_pNext->_val;}T& back(){assert(!empty());return _pHead->_pPre->_val;}const T& back()const{assert(!empty());return _pHead->_pPre->_val;}// List Modifyvoid push_back(const T& val){insert(end(), val);}void pop_back(){erase(--end());}void push_front(const T& val){insert(begin(), val);}void pop_front(){erase(begin());}// 在pos位置前插入值为val的节点iterator insert(iterator pos, const T& val){PNode newnode = new Node(val);PNode cur = pos._pNode;PNode prev = cur->_pPre;newnode->_pPre = prev;newnode->_pNext = cur;prev->_pNext = newnode;cur->_pPre = newnode;return iterator(newnode);}// 删除pos位置的节点,返回该节点的下一个位置iterator erase(iterator pos){assert(pos != end());PNode prev = pos._pNode->_pPre;PNode next = pos._pNode->_pNext;prev->_pNext = next;next->_pPre = prev;delete pos._pNode;return iterator(next);//利用匿名对象返回}void clear(){iterator p = begin();while (p != end()){p = erase(p);}_pHead->_pPre = _pHead;_pHead->_pNext = _pHead;}void swap(list<T>& l){std::swap(_pHead, l._pHead);}private:void CreateHead(){_pHead = new Node;_pHead->_pPre = _pHead;_pHead->_pNext = _pHead;}PNode _pHead;};
}

总结

✨✨✨各位读友,本篇分享到内容是否更好的让你理解了C++的list,如果对你有帮助给个👍赞鼓励一下吧!!
🎉🎉🎉世上没有绝望的处境,只有对处境绝望的人。
感谢每一位一起走到这的伙伴,我们可以一起交流进步!!!一起加油吧!!。

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

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

相关文章

网络空间安全数学基础·整除与同余

主要内容&#xff1a; 整除的基本概念&#xff08;掌握&#xff09; 素数&#xff08;掌握&#xff09; 同余的概念&#xff08;掌握&#xff09; 1.1整除 定义&#xff1a;设a&#xff0c;b是任意两个整数&#xff0c;其中b≠0&#xff0c;如果存在一个整数q&#xff0c;使 …

12306技术内幕

公司内部做的一次技术分享 文章目录 12306的成就12306系统特点12306系统难点解决思路产品角度技术角度余票库存的表如何设计&#xff1f; 抢票软件推荐巨人的肩膀 对于未公开的技术部分&#xff0c;只能结合已公开的信息&#xff0c;去做大胆的猜想。 本文提到的一些解决方案&…

测试基础05:软件测试的分类

课程大纲 1、两种架构&#xff08;Architecture&#xff09; 1.1、B/S&#xff08;Browser/Server&#xff09; 浏览器服务器架构&#xff08;大体3步&#xff09;&#xff1a;用户通过浏览器向服务器发出请求&#xff0c;服务器处理请求&#xff0c;将结果通过网络返回到用户…

使用Webcam实现摄像头的开启和关闭,并保存和复制图片

实现思路 0&#xff0c;将webcam的jar文件传入项目中 1&#xff0c;显示摄像头的地方&#xff1a;创建一个画板&#xff0c;在画板上添加开启和关闭按钮 2&#xff0c;设置开启和关闭功能&#xff1a;创建一个类实现动作监听器&#xff0c;进而实现监听动作按钮 3&#xff…

【数据结构与算法篇】二叉树链式结构及实现

【数据结构与算法篇】二叉树链式结构及实现 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;每日刷题&#x1f34d; &#x1f33c;文章目录&#x1f33c; 4. 二叉树链式结构的实现 4.1 前置说明 4.2 二叉树的遍历 4.2.1 前序、中序以及…

OceanBase的存储架构与传统LSM-Tree架构的异同|OceanBase数据转储合并技术解读(二)

前篇博文将OceanBase的存储架构巧妙地与自然界中的“水生态”进行了类比&#xff0c;今日我们转变视角&#xff0c;聚焦在与拥有相同LSM-Tree架构的其他产品的比较&#xff0c;深入探讨OceanBase相较于它们所展现出的独特性能。 众所周知&#xff0c;OceanBase数据库的存储引擎…

element-ui 前端ui框架用法开发指南(2024-05-22)

Element&#xff0c;一套为开发者、设计师和产品经理准备的基于 Vue 2.0 的桌面端组件库 1、npm安装 // npm安装&#xff1a;npm install element-ui --save 能更好地和 webpack 打包工具配合使用 2、cdn在线引入 访问最新版本的资源地址 - element-uiThe CDN for element-u…

RedHat9 | DNS剖析-配置主DNS服务器实例

一、实验环境 1、BIND软件包介绍 BIND软件是一款开放源码的DNS服务器软件&#xff0c;由美国加州大学Berkeley分校开发和维护&#xff0c;全称为Berkeley Internet Name Domain。该软件在DNS&#xff08;域名系统&#xff09;领域具有重要地位&#xff0c;是目前世界上使用最…

使用OpenCV dnn c++加载YOLOv8生成的onnx文件进行目标检测

在网上下载了60多幅包含西瓜和冬瓜的图像组成melon数据集&#xff0c;使用 LabelMe 工具进行标注&#xff0c;然后使用 labelme2yolov8 脚本将json文件转换成YOLOv8支持的.txt文件&#xff0c;并自动生成YOLOv8支持的目录结构&#xff0c;包括melon.yaml文件&#xff0c;其内容…

Python怎样定位并删除Sql语句中不确定的查询条件

1.问题场景描述: 在sql语句中经常会有查询条件是:查找多个订单签订日期范围的数据,但具体的日期范围是不确定,我们如何来查找定位 例如:查询条件语句的部分如下图: 目标是: 1)定位字符串:t_contract_order.sign_date 2)最终得到结果: 解决问题思路: 1)定位要找的字符串起始位置…

【学习心得】PyTorch的知识要点复习(持续更新)

PyTorch知识要点复习&#xff0c;目的是为了巩固PyTorch基础、快速回顾、深化理解PyTorch框架。这篇文章会持续更新。 一、本文的一些说明 知识点梳理&#xff1a;我将PyTorch的核心概念和高级技巧进行了系统化的整理&#xff0c;从基础的张量操作到复杂的模型构建与训练。这样…

【Linux】进程终止与进程等待

目录 进程终止 errno exit和_exit 进程等待 wait和waitpid 宏&#xff1a;WIFEXITED 非阻塞等待 进程终止 下面要谈的一个话题就是进程终止&#xff0c;就是说一个进程退出了&#xff0c;可能有三种情况 1.进程代码执行完&#xff0c;结果是正确的 2.进程代码执行完&…

【活动】开源与闭源大模型:探索未来趋势的双轨道路

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 开源与闭源大模型&#xff1a;探索未来趋势的双轨道路引言一、开源大模型&#…

翻译《The Old New Thing》- The importance of the FORMAT_MESSAGE_IGNORE_INSERTS flag

The importance of the FORMAT_MESSAGE_IGNORE_INSERTS flag - The Old New Thing (microsoft.com)https://devblogs.microsoft.com/oldnewthing/20071128-00/?p24353 Raymond Chen 2007年11月28日 FORMAT_MESSAGE_IGNORE_INSERTS 标志的重要性 简要 文章讨论了使用FormatMes…

评估企业的业务是否存在高风险的六个步骤

风险的幽灵使得组织别无选择&#xff0c;只能改善各种网络风险的总体管理。以下是一个基于信息安全论坛的IRAM2方法论的分步过程&#xff0c;网络安全和风险从业者可以利用它来评估和管理信息风险。 第1步&#xff1a;范围界定练习 范围界定练习的目标是提供一个以业务为中心…

基于springboot+vue的招聘信息管理系统

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…

K8s的常用命令以及yaml文件的创建

目录 一、声明式管理方法&#xff1a;YAML文件 1、yaml文件简介 2、yaml和json的主要区别&#xff1a; 3、YAML的语法格式 4、yaml文件组成部分 ①控制器定义 5、查看api资源版本标签 6、编写nginx-deployment.yaml资源配置清单 6.1创建资源对象 6.2查看创建的pod资源…

Unity-Sprite Atlas+UGUI系统的运行原理

每日一句&#xff1a;别听世俗耳语&#xff0c;看自己的风景就好 目录 SA的原理&#xff1a; SA的优点&#xff1a; SA的缺点&#xff1a; DrawCall是什么&#xff1f; 批处理是什么&#xff1f; 我们先了解一下UGUI系统的运行原理吧&#xff01; 提到图集优化&#xff0…

cocosCreator动态生成二维码

cocosCreator 版本&#xff1a;3.7.2 开发语言&#xff1a;typeScript 我们在游戏开发中&#xff0c;经常会生成一个专属于玩家个人的二维码&#xff0c;比如说推广、充值等功能。 接到这个任务&#xff0c;在网上找了下&#xff0c;还是有很多教程的。但是这些教程大部分都是用…

Ollydbg动态分析MessageBoxA输出hellow world

一、目的 找到main函数找到调用的MessageBoxA函数 测试源码 #include <iostream> #include <windows.h>int main() {MessageBoxA(NULL, "Hellow World", "Title", MB_OK);return 1; }二、快捷键 指令快捷键说明RestartCtrlF2重新开始调试S…