list的使用,及部分功能的模拟实现(C++)
目录(文章中"节点"和"结点"是同一个意思)
1. 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的迭代器失效
2. list的模拟实现
2.1 list_node结点
2.2 list_iterator迭代器
2.2.1 运算符重载!=
2.2.2 运算符重载==
2.2.3 运算符重载前置++
2.2.4 运算符重载后置++
2.2.5 运算符重载前置--
2.2.6 运算符重载后置--
2.2.7 运算符重载*
2.2.8 运算符重载->
2.3 list类
2.3.1 构造函数
2.3.1.1默认构造函数list
2.3.1.2 拷贝构造
2.3.1.3 list(std::initializer_list lt)
2.3.2 析构函数
2.3.3 赋值运算符重载
2.3.4 front和back
2.3.5 size和begin和end
2.3.6 insert插入和erase删除
2.3.6.1 insert插入
2.3.6.2 erase删除
2.3.7 头插push_front,头删pop_front,尾插push_back,尾删pop_back
2.4 整体代码
1. list的介绍及使用
1.1 list的介绍
std::list是 C++ 标准模板库(STL)中的一个容器类,底层实现为双向链表,适用于需要频繁插入和删除操作的场景。
1.2 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 |
使用演示:
void test1() {list<int> l1(10, 5);list<int> l2;list<int> l3(l1);list<int> l4(l1.begin(),l1.end());for (auto& e : l1){cout << e << " ";}cout << endl;for (auto& e : l2){cout << e << " ";}cout << endl;for (auto& e : l3){cout << e << " ";}cout << endl; for (auto& e : l4){cout << e << " ";}cout << endl; }结果:
1.2.2 list iterator的使用
这里可以暂时将迭代器理解成一个指针,该指针指向list中的某个节点。(其实底层实现时,迭代器是一个封装的对象)
| 函数声明 | 接口说明 |
| begin + end | 返回第一个元素的迭代器+返回最后一个元素下一个位置的迭代器 |
| rbegin + rend | 返回第一个元素的reverse_iterator,即end位置,返回最后一个元素下一个位 置的reverse_iterator,即begin位置 |
1. begin与end为正向迭代器,对迭代器执行++操作,迭代器向后移动
2. rbegin(end)与rend(begin)为反向迭代器,对迭代器执行++操作,迭代器向前移动
使用演示:
void test2() {list<int> l;l.push_back(1);l.push_back(2);l.push_back(3);l.push_back(4);l.push_back(5);list<int>::reverse_iterator rit = l.rbegin();while (rit != l.rend()){cout << *rit << " ";rit++;}cout << endl;list<int>::iterator it = l.begin();while (it != l.end()){cout << *it << " ";it++;}cout << endl; }结果:
1.2.3 list capacity
| 函数声明 | 接口说明 |
| empty | 检测list是否为空,是返回true,否则返回false |
| size | 返回list中有效节点的个数 |
使用演示:
void test3() {list<int> l;l.push_back(1);l.push_back(2);l.push_back(3);l.push_back(4);l.push_back(5);if(!l.empty()){cout << "该链表非空" << endl;}cout << "有效节点个数:" << l.size() << endl; }结果:
1.2.4 list element access
| 函数声明 | 接口说明 |
| front | 返回list的第一个节点中值的引用 |
| back | 返回list的最后一个节点中值的引用 |
使用演示:
void test4() {list<int> l;l.push_back(1);l.push_back(2);l.push_back(3);l.push_back(4);l.push_back(5);cout << l.front() << endl;cout << l.back() << endl; }结果:
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中的有效元素 |
使用演示:
push_front和pop_front使用:
void test5() {list<int> l;l.push_back(1);l.push_back(2);l.push_back(3);l.push_back(4);l.push_back(5);for (auto& e : l){cout << e << " ";}cout << endl;l.push_front(10);cout << "头插后:";for (auto& e : l){cout << e << " ";}cout << endl;l.pop_front();cout << "头删后:";for (auto& e : l){cout << e << " ";}cout << endl; }结果:
push_back和pop_back:
void test6() {list<int> l;l.push_back(1);l.push_back(2);l.push_back(3);l.push_back(4);l.push_back(5);for (auto& e : l){cout << e << " ";}cout << endl;l.push_back(6);cout << "尾插后:";for (auto& e : l){cout << e << " ";}cout << endl;l.pop_back();cout << "尾删后:";for (auto& e : l){cout << e << " ";}cout << endl; }结果:
insert和erase:
void test7() {list<int> l;l.push_back(1);l.push_back(2);l.push_back(3);l.push_back(4);l.push_back(5);for (auto& e : l){cout << e << " ";}cout << endl;l.insert(++l.begin(), 30);cout << "插入后:";for (auto& e : l){cout << e << " ";}cout << endl;l.erase(--l.end());cout << "删除后:";for (auto& e : l){cout << e << " ";}cout << endl; }结果:
swap:
void test8() {list<int> l1;l1.push_back(1);l1.push_back(2);l1.push_back(3);l1.push_back(4);l1.push_back(5);list<int> l2(5, 5);cout << "交换前" << endl;cout << "l1:";for (auto& e : l1){cout << e << " ";}cout << endl;cout << "l2:";for (auto& e : l2){cout << e << " ";}cout << endl;cout << "交换后" << endl;l1.swap(l2);cout << "l1:";for (auto& e : l1){cout << e << " ";}cout << endl;cout << "l2:";for (auto& e : l2){cout << e << " ";}cout << endl; }结果:
clear:
void test9() {list<int> l1;l1.push_back(1);l1.push_back(2);l1.push_back(3);l1.push_back(4);l1.push_back(5);cout << "清空前" << endl;cout << "有效元素个数:" << l1.size() << endl;for (auto& e : l1){cout << e << " ";}cout << endl;l1.clear();cout << "清空后" << endl;cout << "有效元素个数:" << l1.size() << endl;for (auto& e : l1){cout << e << " ";}cout << endl; }结果:
1.2.6 list的迭代器失效
小编前面文章里面“vector迭代器失效”,提到只要使用erase或者insert之后迭代器就直接失效,但是对于list有所不同,迭代器失效即迭代器所指向的节点的无效,即该节点被删除了。因为list的底层结构为带头结点的双向循环链表,因此在list中进行插入时是不会导致list的迭代器失效的,只有在删除时才会失效,并且失效的只是指向被删除节点的迭代器,其他迭代器不会受到影响。
举例(删除所有结点):
void test10() {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 test10() {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()){it=l.erase(it);} }因为erase函数删除后,会返回删除结点的下一个节点迭代器,it接收返回值,相当于更新了迭代器。
2. list的模拟实现
这里利用双向带头链表实现,因为链表的物理空间并不是连续的,所以这里的迭代器不能使用指针,这里对迭代器进行了封装,实现一个对象。还有这里为了和原本库里list区分,将自己写的list封装在命名空间里(作者的是iu)
2.1 list_node结点
template<class T>
struct list_node
{list_node<T>* _prev;list_node<T>* _next;T _value;list_node(const T& x = T()):_prev(nullptr),_next(nullptr),_value(x){}
};
双向带头链表,所以成员有前驱结点,和后继结点,和元素对象。
2.2 list_iterator迭代器
template<class T,class REF,class PTR>
struct list_iterator
{typedef list_node<T> Node;typedef list_iterator<T, REF, PTR> Self;Node* _node;list_iterator(Node* node):_node(node){}};
这里模版为什么会有REF和PTR?其实是解决,范围for迭代器访问时,会有const修饰的对象,如果直接确定的写,只有普通对象可以,所以这里多给两个参数模版,让编译器自己去判断是const修饰的对象,还是普通对象。
2.2.1 运算符重载!=
bool operator!=(const Self& it)
{return _node!=it._node;
}
2.2.2 运算符重载==
bool operator==(const Self& it)
{return _node == it._node;
}
2.2.3 运算符重载前置++
Self& operator++()
{_node = _node->_next;return *this;
}
结点的指向直接向后移动一位。
2.2.4 运算符重载后置++
Self operator++(int)
{Self tmp(*this);_node = _node->_next;return tmp;
}
创建一个临时对象,节点的指向向后移动一位,返回临时对象。
2.2.5 运算符重载前置--
Self& operator--()
{_node = _node->_prev;return *this;
}
结点的指向直接向前移动一位。
2.2.6 运算符重载后置--
Self operator++(int)
{Self tmp(*this);_node = _node->_next;return tmp;
}
创建一个临时对象,节点的指向向前移动一位,返回临时对象。
2.2.7 运算符重载*
REF operator*()
{return _node->_value;
}
解引用,就是返回对象的值。
2.2.8 运算符重载->
PTR operator->()
{return &_node->_value;
}
这里为什么是取值的地址?通过下面的例子来讲解:
void test2() {struct A{A(int a = 0,int b=0):_a(a),_b(b){}int _a;int _b;};iu::list<A>l2;l2.push_back({1,1});l2.push_back({2,2});l2.push_back({3,3});l2.push_back({4,4});iu::list<A>::iterator it = l2.begin();while (it != l2.end()){cout << (*it)._a << ":" << it->_b << endl;it++;} }这里可以利用解引用在去访问,A类中的成员,这是一种访问方式;而这个it->b是如何访问的?前面实现的是返回A的地址,拿到A对象的地址和成员_b之间也没有运算符,那有怎么样才能访问到_b呢?其实这里省略了一个->,这里其实应该是it->->_b,所以先拿到A对象的地址,再利用结构体->这种方式。解引用访问里面的成员。
结果:
2.3 list类
template<class T>class list{typedef list_node<T> Node;public:typedef list_iterator<T,T&,T*> iterator;typedef list_iterator<T, const T&, const T*> const_iterator;private:Node* _head;size_t _size;};
}
成员有头结点,和元素个数。
2.3.1 构造函数
2.3.1.1默认构造函数list
void empty_init()
{_head = new Node;_head->_prev = _head;_head->_next = _head;_size = 0;
}list()
{empty_init();
}
这里利用empty_init函数,进行初始化,是为了方便后面几个构造函数,先初始化,再尾插的操作。
2.3.1.2 拷贝构造
list(const list<T>& lt)
{empty_init();for (auto& e : lt){push_back(e);}
}
初始化,再遍历一遍lt,进行尾插依次插入。
2.3.1.3 list(std::initializer_list<T> lt)
list(std::initializer_list<T> lt)
{empty_init();for (auto& e : lt){push_back(e);}
}
和上面同理。
这里举一个例子:
void test8() {iu::list<int>l1 = { 1,2,3,4,5,6,7 };for (auto& e : l1){cout << e << " ";}cout << endl; }结果:
这个initializer_list<T>类型是一个类似于数组的类型,可以理解成一种类似数组初始化的方式。
2.3.2 析构函数
void clear()
{iterator it = begin();while (it != end()){it = erase(it);}
}~list()
{clear();delete _head;_head = nullptr;
}
先在clear函数里面将数据全部清除,再将头结点释放掉,置为空。
2.3.3 赋值运算符重载
void swap(list<T>& lt)
{std::swap(_head, lt._head);std::swap(_size, lt._size);
}list<T>& operator=(list<T> lt)
{swap(lt);return *this;
}
利用std中的交换函数,将临时对象与this指向的对象进行交换,临时对象出了作用域会自然销毁,也不会影响实参,这样就相当于实现了赋值操作。
2.3.4 front和back
T& front()
{return _head->_next->_value;
}const T& front()const
{return _head->_next->_value;
}
T& back()
{return _head->_prev->_value;
}
const T& back()const
{return _head->_prev->_value;
}
这里利用的是双向带头链表,所以头部front元素就是头结点的下一个,尾结点back就是头结点的前一个。这里还重载了const修饰的对象,当对象元素是不可改变的const时,也可以使用。
2.3.5 size和begin和end
size_t size()
{return _size;
}iterator begin()
{return _head->_next;
}iterator end()
{return _head;
}const_iterator begin() const
{return _head->_next;
}const_iterator end() const
{return _head;
}
size函数,直接返回成员_size大小即可。
begin()返回头结点的下一个结点的迭代器,end()返回最后一个元素的下一个结点的迭代器,所以就是头结点head,这里也是重载了const修饰的对象,当对象元素是不可改变的const时,也可以使用。
2.3.6 insert插入和erase删除
2.3.6.1 insert插入
void insert(iterator pos,const T& x)
{Node* newnode = new Node(x);Node* cur = pos._node;Node* prev = cur->_prev;prev->_next = newnode;newnode->_prev = prev;newnode->_next = cur;cur->_prev = newnode;++_size;
}
首先创建一个新的结点,再进行插入操作,插入时,先找到pos位置的结点,和pos位置的前一个结点,再改变前后指针指向即可,最后_size再加1。
2.3.6.2 erase删除
iterator erase(iterator pos)
{assert(pos != end());Node* del = pos._node;Node* prev = del->_prev;Node* next = del->_next;prev->_next = next;next->_prev = prev;delete del;--_size;return iterator(next);
}
首先找到pos位置的结点,再确定pos前一个结点,和后一个结点的位置,最后改变指针指向,再删除pos位置的节点,_size再减1,最后还要返回删除节点的下一个位置的结点,返回匿名对象即可。
2.3.7 头插push_front,头删pop_front,尾插push_back,尾删pop_back
void push_back(const T& x)
{insert(end(), x);
}
void push_front(const T& x)
{insert(begin(), x);
}
void pop_back()
{erase(--end());
}void pop_front()
{erase(begin());
}
这里直接复用insert和erase函数实现,只是要注意尾结点的位置是end()的前一个位置。
例子:
void test4() {iu::list<int>l1;l1.push_back(1);l1.push_back(2);l1.push_back(3);l1.push_back(4);l1.insert(l1.begin(), 10);l1.insert(l1.begin(), 20);for (auto& e : l1){cout << e << " ";}cout << endl;l1.pop_back();l1.pop_back();l1.pop_front();l1.pop_front();for (auto& e : l1){cout << e << " ";}cout << endl; }结果:
2.4 整体代码
#include<assert.h>
#include<algorithm>
#include <initializer_list>namespace iu
{template<class T>struct list_node{list_node<T>* _prev;list_node<T>* _next;T _value;list_node(const T& x = T()):_prev(nullptr),_next(nullptr),_value(x){}};template<class T,class REF,class PTR>struct list_iterator{typedef list_node<T> Node;typedef list_iterator<T, REF, PTR> Self;Node* _node;list_iterator(Node* node):_node(node){}bool operator!=(const Self& it){return _node!=it._node;}bool operator==(const Self& it){return _node == it._node;}REF operator*(){return _node->_value;}PTR operator->(){return &_node->_value;}Self& operator++(){_node = _node->_next;return *this;}Self& operator--(){_node = _node->_prev;return *this;}Self operator++(int){Self tmp(*this);_node = _node->_next;return tmp;}Self operator--(int){Self tmp(*this);_node = _node->_prev;return tmp;}};template<class T>class list{typedef list_node<T> Node;public:typedef list_iterator<T,T&,T*> iterator;typedef list_iterator<T, const T&, const T*> const_iterator;void empty_init(){_head = new Node;_head->_prev = _head;_head->_next = _head;_size = 0;}list(){empty_init();}void swap(list<T>& lt){std::swap(_head, lt._head);std::swap(_size, lt._size);}list<T>& operator=(list<T> lt){swap(lt);return *this;}list(std::initializer_list<T> lt){empty_init();for (auto& e : lt){push_back(e);}}list(const list<T>& lt)//拷贝构造{empty_init();for (auto& e : lt){push_back(e);}}~list(){clear();delete _head;_head = nullptr;}void clear(){iterator it = begin();while (it != end()){it = erase(it);}}T& front(){return _head->_next->_value;}const T& front()const{return _head->_next->_value;}T& back(){return _head->_prev->_value;}const T& back()const{return _head->_prev->_value;}size_t size(){return _size;}iterator begin(){return _head->_next;}iterator end(){return _head;}const_iterator begin() const{return _head->_next;}const_iterator end() const{return _head;}void push_back(const T& x){//Node* newnode = new Node(x);//Node* tail = _head->_prev;//newnode->_prev = tail;//tail->_next = newnode;//newnode->_next = _head;//_head->_prev = newnode;insert(end(), x);}void push_front(const T& x){insert(begin(), x);}void insert(iterator pos,const T& x){Node* newnode = new Node(x);Node* cur = pos._node;Node* prev = cur->_prev;prev->_next = newnode;newnode->_prev = prev;newnode->_next = cur;cur->_prev = newnode;++_size;}iterator erase(iterator pos){assert(pos != end());Node* del = pos._node;Node* prev = del->_prev;Node* next = del->_next;prev->_next = next;next->_prev = prev;delete del;--_size;return iterator(next);}void pop_back(){erase(--end());}void pop_front(){erase(begin());}private:Node* _head;size_t _size;};
}相关文章:
list的使用,及部分功能的模拟实现(C++)
目录(文章中"节点"和"结点"是同一个意思) 1. 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…...
联想Y7000+RTX4060+i7+Ubuntu22.04运行DeepSeek开源多模态大模型Janus-Pro-1B+本地部署
直接上手搓了: conda create -n myenv python3.10 -ygit clone https://github.com/deepseek-ai/Janus.gitcd Januspip install -e .pip install webencodings beautifulsoup4 tinycss2pip install -e .[gradio]pip install pexpect>4.3python demo/app_januspr…...
[Spring] Gateway详解
🌸个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 🏵️热门专栏: 🧊 Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm1001.2014.3001.5482 🍕 Collection与…...
音叉模态分析
目录 0 序言 1 自由状态下模态求解 1.1 添加模态项目 1.2 生成网格 1.3 设置最大模态阶数 1.4 求解 1.5 结果查看 1.6 结果分析 2 音叉能否释放频率440Hz的音调 3 预应力模态求解 3.1 静态结构分析 3.1.1 添加静态结构项目 3.1.2生成网格 3.1.3添加边界条件 3.1…...
BW AO/工作簿权限配置
场景: 按事业部配置工作簿权限; 1、创建用户 事务码:SU01,用户主数据的维护,可以创建、修改、删除、锁定、解锁、修改密码等 用户设置详情页 2、创建权限角色 用户的权限菜单是通过权限角色分配来实现的 2.1、自定…...
C++ 字母大小写转换两种方法统计数字字符的个数
目录 题目: 代码1: 代码2: 题目描述输入一行字符,统计出其中数字字符的个数。 代码如下: 判断⼀个字符是否是数字字符有⼀个函数是 isdigit ,可以直接使⽤。 代码如下: 题目: 大家都知道…...
如何使用 ChatBox AI 简化本地模型对话操作
部署模型请看上一篇帖子:本地部署DeepSeek教程(Mac版本)-CSDN博客 使用 ChatBox AI 简化本地模型对话操作: 打开 ChatBox AI 官网:Chatbox AI官网:办公学习的AI好助手,全平台AI客户端…...
前端面试笔试题目(一)
以下模拟了大厂前端面试流程,并给出了涵盖HTML、CSS、JavaScript等基础和进阶知识的前端笔试题目,以帮助你更好地准备面试。 面试流程模拟 1. 自我介绍(5 - 10分钟):面试官会请你进行简单的自我介绍,包括…...
Docker Hello World
Docker Hello World 引言 Docker 是一个开源的应用容器引擎,可以让开发者打包他们的应用以及应用的依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。本文将带领您从零开始,学习如何使用 Docker 运行一个简单的 "Hello World"…...
UE 5.3 C++ 对垃圾回收的初步认识
一.UObject的创建 UObject 不支持构造参数。 所有的C UObject都会在引擎启动的时候初始化,然后引擎会调用其默认构造器。如果没有默认的构造器,那么 UObject 将不会编译。 有修改父类参数的需求,就使用指定带参构造 // Sets default value…...
ARM内核:嵌入式时代的核心引擎
引言 在当今智能设备无处不在的时代,ARM(Advanced RISC Machines)处理器凭借其高性能、低功耗的特性,成为智能手机、物联网设备、汽车电子等领域的核心引擎。作为精简指令集(RISC)的典范,ARM核…...
需求分析应该从哪些方面来着手做?
需求分析一般可从以下几个方面着手: 业务需求方面 - 与相关方沟通:与业务部门、客户等进行深入交流,通过访谈、问卷调查、会议讨论等方式,明确他们对项目的期望、目标和整体业务需求,了解项目要解决的业务问题及达成的…...
【Unity2D 2022:C#Script】DoTween插件的使用
一、插件介绍 DOTween 是一个快速、高效、完全类型安全的 Unity 面向对象的动画引擎,针对 C# 用户进行了优化,免费和开源,具有大量高级功能 二、插件的下载 1. DoTween官网:DOTween (HOTween v2) 2. DoTween下载: …...
【Docker】ubuntu中 Docker的使用
之前记录了 docker的安装 【环境配置】ubuntu中 Docker的安装; 本篇博客记录Dockerfile的示例,docker 的使用,包括镜像的构建、容器的启动、docker compose的使用等。 当安装好后,可查看docker的基本信息 docker info ## 查…...
【数据结构篇】时间复杂度
一.数据结构前言 1.1 数据结构的概念 数据结构(Data Structure)是计算机存储、组织数据的⽅式,指相互之间存在⼀种或多种特定关系的数 据元素的集合。没有⼀种单⼀的数据结构对所有⽤途都有⽤,所以我们要学各式各样的数据结构, 如:…...
linux 环境安装 dlib 的 gpu 版本
默认使用 pip 安装的 dlib 是不使用 gpu 的 在国内社区用百度查如何安装 gpu 版本的 dlib 感觉信息都不太对,都是说要源码编译还有点复杂 还需要自己安装 cuda 相关的包啥的,看着就头大 于是想到这个因该 conda 自己就支持了吧,然后查了一下…...
springboot集成钉钉,发送钉钉日报
目录 1.说明 2.示例 3.总结 1.说明 学习地图 - 钉钉开放平台 在钉钉开放文档中可以查看有关日志相关的api,主要用到以下几个api: ①获取模板详情 ②获取用户发送日志的概要信息 ③获取日志接收人员列表 ④创建日志 发送日志时需要根据模板规定日志…...
【机器学习】自定义数据集 使用scikit-learn中svm的包实现svm分类
一、支持向量机(support vector machines. ,SVM)概念 1. SVM 绪论 支持向量机(SVM)的核心思想是找到一个最优的超平面,将不同类别的数据点分开。SVM 的关键特点包括: ① 分类与回归: SVM 可以用于分类&a…...
快速提升网站收录:利用网站历史数据
本文转自:百万收录网 原文链接:https://www.baiwanshoulu.com/38.html 利用网站历史数据可以有效提升网站的收录速度,以下是一些具体的策略和方法: 一、理解网站历史数据的重要性 网站历史数据记录了网站过去的运营情况、用户行…...
【Git】初识Git Git基本操作详解
文章目录 学习目标Ⅰ. 初始 Git💥注意事项 Ⅱ. Git 安装Linux-centos安装Git Ⅲ. Git基本操作一、创建git本地仓库 -- git init二、配置 Git -- git config三、认识工作区、暂存区、版本库① 工作区② 暂存区③ 版本库④ 三者的关系 四、添加、提交更改、查看提交日…...
Java 语言特性(面试系列2)
一、SQL 基础 1. 复杂查询 (1)连接查询(JOIN) 内连接(INNER JOIN):返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...
CTF show Web 红包题第六弹
提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框,很难让人不联想到SQL注入,但提示都说了不是SQL注入,所以就不往这方面想了 先查看一下网页源码,发现一段JavaScript代码,有一个关键类ctfs…...
【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器
一.自适应梯度算法Adagrad概述 Adagrad(Adaptive Gradient Algorithm)是一种自适应学习率的优化算法,由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率,适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...
【位运算】消失的两个数字(hard)
消失的两个数字(hard) 题⽬描述:解法(位运算):Java 算法代码:更简便代码 题⽬链接:⾯试题 17.19. 消失的两个数字 题⽬描述: 给定⼀个数组,包含从 1 到 N 所有…...
如何在看板中有效管理突发紧急任务
在看板中有效管理突发紧急任务需要:设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP(Work-in-Progress)弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中,设立专门的紧急任务通道尤为重要,这能…...
《C++ 模板》
目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板,就像一个模具,里面可以将不同类型的材料做成一个形状,其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式:templa…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)
本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...
C++ 设计模式 《小明的奶茶加料风波》
👨🎓 模式名称:装饰器模式(Decorator Pattern) 👦 小明最近上线了校园奶茶配送功能,业务火爆,大家都在加料: 有的同学要加波霸 🟤,有的要加椰果…...
数学建模-滑翔伞伞翼面积的设计,运动状态计算和优化 !
我们考虑滑翔伞的伞翼面积设计问题以及运动状态描述。滑翔伞的性能主要取决于伞翼面积、气动特性以及飞行员的重量。我们的目标是建立数学模型来描述滑翔伞的运动状态,并优化伞翼面积的设计。 一、问题分析 滑翔伞在飞行过程中受到重力、升力和阻力的作用。升力和阻力与伞翼面…...












