C++ -- STL-- List

       //////     欢迎来到 aramae 的博客,愿 Bug 远离,好运常伴!  //////

博主的Gitee地址:阿拉美 (aramae) - Gitee.com

时代不会辜负长期主义者,愿每一个努力的人都能达到理想的彼岸。

  • 1. list的介绍及使用
  • 2. list的深度剖析及模拟实现
  • 3. listvector的对比   
引言: 本章学习STL中的List容器,包括 list 的介绍及使用,深度剖析及模拟实现并补充和 vector的差异。

1. list的介绍及使用

1.1 list的介绍

  • 1. list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。
  • 2. list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向 其前一个元素和后一个元素。
  • 3. list与forward_list非常相似:最主要的不同在于forward_list是单链表,只能朝前迭代,已让其更简单高效。
  • 4. 与其他的序列式容器相比(array,vector,deque),list通常在任意位置进行插入、移除元素的执行效率 更好。
  • 5. 与其他序列式容器相比,list和forward_list最大的缺陷是不支持任意位置的随机访问,比如:要访问list 的第6个元素,必须从已知的位置(比如头部或者尾部)迭代到该位置,在这段位置上迭代需要线性的时间 开销;list还需要一些额外的空间,以保存每个节点的相关联信息(对于存储类型较小元素的大list来说这 可能是一个重要的因素)

https://cplusplus.com/reference/list/list/?kw=listhttps://cplusplus.com/reference/list/list/?kw=list


1.2 list的使用 

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

1.2.1 list的构造

 list的构造使用代码演示:
#include <iostream>
#include <list>
#include <vector>
using namespace std;// 打印 list 内容的函数
template <typename T>
void printList(const list<T>& lst, const string& desc) {cout << desc << ": ";for (const auto& elem : lst) {cout << elem << " ";}cout << endl;
}int main() {// 1. 默认构造函数 list()list<int> lst1;lst1.push_back(1);lst1.push_back(2);printList(lst1, "1. 默认构造后添加元素");// 2. 构造包含 n 个 val 的 list:list (size_type n, const value_type& val)list<int> lst2(5, 10);  // 构造包含 5 个 10 的 listprintList(lst2, "2. 构造 5 个 10 的 list");// 3. 拷贝构造函数 list (const list& x)list<int> lst3(lst2);  // 用 lst2 拷贝构造 lst3printList(lst3, "3. 拷贝 lst2 构造 lst3");// 4. 范围构造函数 list (InputIterator first, InputIterator last)vector<int> vec = {100, 200, 300};list<int> lst4(vec.begin(), vec.end());  // 用 vector 的 [begin, end) 范围构造printList(lst4, "4. 用 vector 范围构造 lst4");// 也可以用 list 自身的迭代器范围构造list<int> lst5(lst4.begin(), lst4.end());printList(lst5, "4. 用 lst4 范围构造 lst5");return 0;
}

1.2.2 list iterator的使用

 将迭代器理解成一个指针,该指针指向list中的某个节点

【注意】
1. begin与end为正向迭代器,对迭代器执行++操作,迭代器向后移动
2. rbegin(end)与rend(begin)为反向迭代器,对迭代器执行++操作,迭代器向前移动

 list的迭代器使用代码演示:
#include <iostream>
#include <list>
#include <string>
using namespace std;// 打印 list 内容(普通迭代器遍历)
template <typename T>
void printListNormal(const list<T>& lst, const string& desc) {cout << desc << ": ";// begin 返回指向第一个元素的迭代器,end 返回指向最后一个元素下一个位置的迭代器for (auto it = lst.begin(); it != lst.end(); ++it) {cout << *it << " ";}cout << endl;
}// 打印 list 内容(反向迭代器遍历)
template <typename T>
void printListReverse(const list<T>& lst, const string& desc) {cout << desc << ": ";// rbegin 返回指向最后一个元素的反向迭代器(对应普通迭代器的 end 前一个位置)// rend 返回指向第一个元素前一个位置的反向迭代器(对应普通迭代器的 begin 位置)for (auto it = lst.rbegin(); it != lst.rend(); ++it) {cout << *it << " ";}cout << endl;
}// 演示普通迭代器修改元素(需要非 const list)
template <typename T>
void modifyWithIterator(list<T>& lst) {cout << "尝试用普通迭代器修改元素:" << endl;for (auto it = lst.begin(); it != lst.end(); ++it) {// 通过解引用迭代器修改元素值(需确保 list 非 const)*it *= 2;  }
}int main() {list<int> myList = {1, 2, 3, 4, 5};// 1. 普通迭代器遍历(begin + end)printListNormal(myList, "普通迭代器遍历初始 list");// 2. 反向迭代器遍历(rbegin + rend)printListReverse(myList, "反向迭代器遍历初始 list");// 3. 用普通迭代器修改元素modifyWithIterator(myList);printListNormal(myList, "修改后的 list(普通迭代器遍历)");printListReverse(myList, "修改后的 list(反向迭代器遍历)");// 4. 结合 const list 演示(只能读,不能通过迭代器修改)const list<int> constList = {10, 20, 30};cout << "const list 遍历(普通迭代器):";for (auto it = constList.begin(); it != constList.end(); ++it) {cout << *it << " ";}cout << endl;return 0;
}

1.2.3 list capacity

  • empty:判断 list 是否为空,返回 bool 类型结果(空为 true,非空为 false )。
  • size:获取 list 中有效元素(节点)的数量,返回 size_type 类型值 。
代码演示:
#include <iostream>
#include <list>int main() {// 创建一个空的 liststd::list<int> myList;// 使用 empty() 检查是否为空std::cout << "myList 是否为空? " << (myList.empty() ? "是" : "否") << std::endl;// 使用 size() 获取元素数量std::cout << "myList 的元素数量: " << myList.size() << std::endl;// 添加元素myList.push_back(10);myList.push_back(20);myList.push_back(30);// 再次检查状态std::cout << "\n添加元素后:" << std::endl;std::cout << "myList 是否为空? " << (myList.empty() ? "是" : "否") << std::endl;std::cout << "myList 的元素数量: " << myList.size() << std::endl;// 清空 listmyList.clear();// 最后一次检查std::cout << "\n清空后:" << std::endl;std::cout << "myList 是否为空? " << (myList.empty() ? "是" : "否") << std::endl;std::cout << "myList 的元素数量: " << myList.size() << std::endl;return 0;
}

 1.2.4 list element access

  • front():返回第一个节点的值的引用,可直接读取或修改(需确保 list 非空,否则行为未定义)。
  • back():返回最后一个节点的值的引用,同理需确保 list 非空。
 代码演示:
#include <iostream>
#include <list>
using namespace std;int main() {// 1. 初始化一个非空 listlist<int> myList = {10, 20, 30};// 2. front:访问并输出第一个节点的值cout << "第一个节点的值(front):" << myList.front() << endl;// 3. back:访问并输出最后一个节点的值cout << "最后一个节点的值(back):" << myList.back() << endl;// 4. 通过 front/back 修改首尾元素(利用引用特性)myList.front() = 100;  // 修改第一个节点为 100myList.back() = 300;   // 修改最后一个节点为 300cout << "修改后 list 的元素:";for (int num : myList) {cout << num << " ";}cout << endl;// 5. 测试空 list(危险操作,实际开发需避免)list<int> emptyList;// 以下两行代码会导致未定义行为(空容器访问 front/back)// cout << emptyList.front(); // cout << emptyList.back(); // 正确做法:先判断 empty()if (!emptyList.empty()) {cout << emptyList.front();} else {cout << "list 为空,无法访问 front/back" << endl;}return 0;
}

1.2.5 list modifiers

1.push_front / pop_front

  • push_front 在链表头部快速插入元素(双向链表结构保证 O(1) 时间复杂度)。
  • pop_front 删除头部元素,同样是 O(1) 复杂度。

2. push_back / pop_back

  • push_back 在链表尾部插入元素,O(1) 时间。
  • pop_back 删除尾部元素,O(1) 时间。

3.insert

  • 需要传入迭代器指定位置,在该位置前插入新元素。
  • 由于是链表结构,插入操作仅需调整指针,O(1) 时间(找到位置的遍历是 O(n),但插入本身是 O(1))。

4. erase

  • 传入迭代器指定要删除的位置,删除该元素并返回下一个位置的迭代器(示例中简化处理,直接移动迭代器)。
  • 同样利用链表结构,删除操作 O(1) 时间(遍历找位置是 O(n),删除本身 O(1))。

5. swap

  • 交换两个 list 的内部数据,时间复杂度 O(1)(仅交换链表头指针等少量数据)。

6. clear

  • 清空链表所有元素,释放内存,所有迭代器失效。
list的插入和删除使用代码演示 :
#include <iostream>
#include <list>
using namespace std;// 打印 list 内容的函数
template <typename T>
void printList(const list<T>& lst, const string& desc) {cout << desc << ": ";for (const auto& elem : lst) {cout << elem << " ";}cout << endl;
}int main() {list<int> myList = {10, 20, 30};// 1. push_front:在首元素前插入myList.push_front(5);printList(myList, "push_front(5) 后"); // 输出: 5 10 20 30 // 2. pop_front:删除第一个元素myList.pop_front();printList(myList, "pop_front() 后");    // 输出: 10 20 30 // 3. push_back:在尾部插入myList.push_back(40);printList(myList, "push_back(40) 后");  // 输出: 10 20 30 40 // 4. pop_back:删除最后一个元素myList.pop_back();printList(myList, "pop_back() 后");     // 输出: 10 20 30 // 5. insert:在指定位置插入auto it = myList.begin();advance(it, 1); // 迭代器移动到第 2 个元素位置(值为 20)myList.insert(it, 15); printList(myList, "insert 后");         // 输出: 10 15 20 30 // 6. erase:删除指定位置元素it = myList.begin();advance(it, 2); // 迭代器移动到第 3 个元素位置(值为 20)myList.erase(it); printList(myList, "erase 后");          // 输出: 10 15 30 // 7. swap:交换两个 list 的元素list<int> anotherList = {100, 200};myList.swap(anotherList);printList(myList, "swap 后 myList");    // 输出: 100 200 printList(anotherList, "swap 后 anotherList"); // 输出: 10 15 30 // 8. clear:清空 listmyList.clear();printList(myList, "clear 后 myList");   // 输出: (空)return 0;
}

1.2.6 list的迭代器失效

前面说过,此处大家可将迭代器暂时理解成类似于指针,迭代器失效即迭代器所指向的节点的无效,即该节点被删除了。因为list的底层结构为带头结点的双向循环链表,因此在list中进行插入时是不会导致list的迭代器失效的,只有在删除时才会失效,并且失效的只是指向被删除节点的迭代器,其他迭代器不会受到影响

下面是几个 std::list 迭代器失效的典型例子及分析:

例子 1:删除操作导致迭代器失效

#include <iostream>
#include <list>int main() {std::list<int> myList = {1, 2, 3, 4, 5};auto it = myList.begin();std::advance(it, 2); // 让 it 指向值为 3 的元素// 错误做法:删除元素后继续使用原迭代器myList.erase(it); // 下面这行代码会导致未定义行为,因为 it 已经失效// std::cout << *it << std::endl; // 正确做法:使用 erase 的返回值更新迭代器auto itCorrect = myList.begin();std::advance(itCorrect, 2); itCorrect = myList.erase(itCorrect);if (itCorrect != myList.end()) {std::cout << "正确处理后下一个元素的值: " << *itCorrect << std::endl;}return 0;
}

解释:在 std::list 中调用 erase 删除元素时,指向被删除元素的迭代器会失效。正确的做法是使用 erase 函数返回的迭代器(指向下一个有效元素)来更新原来的迭代器。

例子 2:清空容器导致迭代器失

#include <iostream>
#include <list>int main() {std::list<int> myList = {1, 2, 3};auto it = myList.begin();myList.clear();// 以下操作会导致未定义行为,因为 myList 已经清空,所有迭代器都失效了// std::cout << *it << std::endl; return 0;
}

解释:当调用 clear 函数清空 std::list 时,所有指向该容器元素的迭代器都会失效,此时再使用这些迭代器访问元素就会产生未定义行为。

例子 3:交换容器导致迭代器失效(相对原容器)

#include <iostream>
#include <list>int main() {std::list<int> list1 = {1, 2, 3};std::list<int> list2 = {4, 5, 6};auto it = list1.begin();list1.swap(list2);// 此时 it 仍然指向原来 list1 中的某个元素,但该元素现在属于 list2 了// 以下操作虽然不会崩溃,但不符合预期,因为 it 不再是 list1 的有效迭代器// std::cout << *it << std::endl; return 0;
}

解释:调用 swap 函数交换两个 std::list 时,迭代器所指向的元素虽然没有被销毁,但所属的容器发生了变化,对于原容器来说,原来的迭代器就失效了。

通过这些例子可以看出,在对 std::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++); // it = l.erase(it);}
}

2. list的模拟实现

2.1 模拟实现list

要模拟实现list,必须要熟悉list的底层结构以及其接口的含义,通过上面的学习,这些内容已基本掌握,现在我们来模拟实现list。


list.h
#include<assert.h>namespace aramae
{template<class T>struct list_node{list_node<T>* _next;list_node<T>* _prev;T _val;list_node(const T& val = T()):_next(nullptr), _prev(nullptr), _val(val){}};// typedef __list_iterator<T, T&, T*> iterator;// typedef __list_iterator<T, const T&, const T*> const_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 operator*(){return _node->_val;}Ptr operator->(){return &_node->_val;}self& operator++(){_node = _node->_next;return *this;}self operator++(int){self tmp(*this);_node = _node->_next;return tmp;}self& operator--(){_node = _node->_prev;return *this;}self operator--(int){self tmp(*this);_node = _node->_prev;return tmp;}bool operator!=(const self& it) const{return _node != it._node;}bool operator==(const self& it) const{return _node == it._node;}};/*template<class T>struct __list_const_iterator{typedef list_node<T> Node;Node* _node;__list_const_iterator(Node* node):_node(node){}const T& operator*(){return _node->_val;}__list_const_iterator<T>& operator++(){_node = _node->_next;return *this;}__list_const_iterator<T> operator++(int){__list_const_iterator<T> tmp(*this);_node = _node->_next;return tmp;}bool operator!=(const __list_const_iterator<T>& it){return _node != it._node;}bool operator==(const __list_const_iterator<T>& it){return _node == it._node;}};*/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;// 如何设计const迭代器?iterator begin(){//return _head->_next;return iterator(_head->_next);}iterator end(){return _head;//return iterator(_head);}const_iterator begin() const{//return _head->_next;return const_iterator(_head->_next);}const_iterator end() const{return _head;//return const_iterator(_head);}void empty_init(){_head = new Node;_head->_prev = _head;_head->_next = _head;_size = 0;}list(){empty_init();}// lt2(lt1)list(const list<T>& lt)//list(const list& lt){empty_init();for (auto& e : lt){push_back(e);}}void swap(list<T>& lt){std::swap(_head, lt._head);std::swap(_size, lt._size);}list<T>& operator=(list<T> lt)//list& operator=(list lt){swap(lt);return *this;}~list(){clear();delete _head;_head = nullptr;}void clear(){iterator it = begin();while (it != end()){it = erase(it);}_size = 0;}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());}// pos位置之前插入iterator insert(iterator pos, const T& x){Node* cur = pos._node;Node* prev = cur->_prev;Node* newnode = new Node(x);prev->_next = newnode;newnode->_next = cur;cur->_prev = newnode;newnode->_prev = prev;++_size;return newnode;}iterator erase(iterator pos){assert(pos != end());Node* cur = pos._node;Node* prev = cur->_prev;Node* next = cur->_next;prev->_next = next;next->_prev = prev;delete cur;--_size;return next;}size_t size(){/*size_t sz = 0;iterator it = begin();while (it != end()){++sz;++it;}return sz;*/return _size;}private:Node* _head;size_t _size;};void Print(const list<int>& lt){list<int>::const_iterator it = lt.begin();while (it != lt.end()){// (*it) += 1;cout << *it << " ";++it;}cout << endl;}void test_list1(){list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);list<int>::iterator it = lt.begin();while (it != lt.end()){(*it) += 1;cout << *it << " ";++it;}cout << endl;for (auto e : lt){cout << e << " ";}cout << endl;Print(lt);}struct A{A(int a1 = 0, int a2 = 0):_a1(a1), _a2(a2){}int _a1;int _a2;};void test_list2(){list<A> lt;lt.push_back(A(1, 1));lt.push_back(A(2, 2));lt.push_back(A(3, 3));lt.push_back(A(4, 4));list<A>::iterator it = lt.begin();while (it != lt.end()){//cout << (*it)._a1 << " " << (*it)._a2 << endl;cout << it->_a1 << " " << it->_a2 << endl;++it;}cout << endl;}void test_list3(){list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);lt.push_front(5);lt.push_front(6);lt.push_front(7);lt.push_front(8);for (auto e : lt){cout << e << " ";}cout << endl;lt.pop_front();lt.pop_back();for (auto e : lt){cout << e << " ";}cout << endl;lt.clear();lt.push_back(10);lt.push_back(20);lt.push_back(30);lt.push_back(40);for (auto e : lt){cout << e << " ";}cout << endl;cout << lt.size() << endl;}void test_list4(){list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);for (auto e : lt){cout << e << " ";}cout << endl;list<int> lt1(lt);for (auto e : lt1){cout << e << " ";}cout << endl;list<int> lt2;lt2.push_back(10);lt2.push_back(20);lt2.push_back(30);lt2.push_back(40);for (auto e : lt2){cout << e << " ";}cout << endl;lt1 = lt2;for (auto e : lt1){cout << e << " ";}cout << endl;}
}

2.2 list的反向迭代器

通过前面例子知道,反向迭代器的++就是正向迭代器的--,反向迭代器的--就是正向迭代器的++,因此反向迭代器的实现可以借助正向迭代器,即:反向迭代器内部可以包含一个正向迭代器,对正向迭代器的接口进行包装即可。

template<class Iterator>
class ReverseListIterator
{// 注意:此处typename的作用是明确告诉编译器,Ref是Iterator类中的类型,而不是静态成员变量// 否则编译器编译时就不知道Ref是Iterator中的类型还是静态成员变量// 因为静态成员变量也是按照 类名::静态成员变量名 的方式访问的
public:typedef typename Iterator::Ref Ref;typedef typename Iterator::Ptr Ptr;typedef ReverseListIterator<Iterator> Self;
public://////////////////////////////////////////////// 构造ReverseListIterator(Iterator it): _it(it){}//////////////////////////////////////////////// 具有指针类似行为Ref operator*(){Iterator temp(_it);--temp;return *temp;}Ptr operator->(){ return &(operator*());}//////////////////////////////////////////////// 迭代器支持移动Self& operator++(){--_it;return *this;}Self operator++(int){Self temp(*this);--_it;return temp;}Self& operator--(){++_it;return *this;}Self operator--(int){Self temp(*this);++_it;return temp;}//////////////////////////////////////////////// 迭代器支持比较bool operator!=(const Self& l)const{ return _it != l._it;}bool operator==(const Self& l)const{ return _it != l._it;}Iterator _it;
};

3. list与vector的对比

vector与list都是STL中非常重要的序列式容器,由于两个容器的底层结构不同,导致其特性以及应用场景不 同,其主要不同如下:

#include <iostream>
#include <list>
#include <vector>int main() {// list 示例std::list<int> myList;myList.push_back(1);  // 在尾部插入元素myList.push_front(0); // 在头部插入元素// 遍历 liststd::cout << "List elements: ";for (const auto& element : myList) {std::cout << element << " ";}std::cout << std::endl;// vector 示例std::vector<int> myVector;myVector.push_back(10); // 在尾部插入元素myVector.push_back(20);// 通过下标访问 vector 元素std::cout << "Vector element at index 0: " << myVector[0] << std::endl;// 遍历 vectorstd::cout << "Vector elements: ";for (const auto& element : myVector) {std::cout << element << " ";}std::cout << std::endl;return 0;
}


结语:感谢相遇

/// 高山仰止,景行行止。虽不能至,心向往之 ///

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

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

相关文章

rt-thread 线程间同步方法详解

rt-thread 线程间同步方法详解一、什么是线程间同步线程同步的必要性线程同步的挑战二、同步方式1、信号量信号量工作机制信号量的管理方式信号量的创建与删除信号量的获取与释放信号量的典型应用场景信号量的注意事项2、互斥量互斥量工作机制互斥量的特性互斥量的操作接口互斥…

Spring Boot + Vue2 实现腾讯云 COS 文件上传:从零搭建分片上传系统

目录 一、项目目标 二、腾讯云 COS 基本配置 1. 创建存储桶 2. 获取 API 密钥 3. 设置跨域规则&#xff08;CORS&#xff09; 三、后端&#xff08;Spring Boot&#xff09;实现 1. 依赖配置 2. 配置腾讯云 COS&#xff08;application.yml&#xff09; 3. 初始化 COS…

使用 Java 获取 PDF 页面信息(页数、尺寸、旋转角度、方向、标签与边框)

目录 引言 一、安装和引入PDF处理库 二、获取 PDF 页数 三、获取页面尺寸&#xff08;宽高&#xff09; 四、获取页面旋转角度 五、判断页面方向&#xff08;横向 / 纵向&#xff09; 六、获取页面标签 七、获取页面边框信息 八、总结 引言 了解 PDF 页面属性是我们在…

基于 AI 的大前端安全态势感知与应急响应体系建设

大前端应用&#xff08;Web、APP、小程序&#xff09;作为用户交互的入口&#xff0c;面临日益复杂的安全威胁&#xff1a;从传统的 XSS 攻击、CSRF 伪造&#xff0c;到新型的供应链投毒、AI 驱动的自动化爬虫&#xff0c;再到针对业务逻辑的欺诈攻击&#xff08;如薅羊毛、账号…

Java 与 MySQL 性能优化:MySQL全文检索查询优化实践

文章目录一、引言二、InnoDB引擎下的全文检索功能详解2.1 全文索引的基本概念与原理2.2 全文索引的创建与管理2.3 全文检索的三种查询模式2.4 中文全文检索的挑战与解决方案三、CMS 场景下的全文检索性能瓶颈分析3.1 索引构建与维护开销3.2 查询性能瓶颈3.3 锁机制与并发性能问…

应用软件格式渗透 利用word去渗透(MS10-087)

用到的靶机为&#xff1a;WinXP漏洞原理&#xff1a;一、漏洞触发机制与核心组件 漏洞根源&#xff1a;RTF文件解析逻辑缺陷 触发组件&#xff1a;Microsoft Word的RTF&#xff08;Rich Text Format&#xff09;解析引擎&#xff0c;具体涉及 mso.dll 模块中的 路径规范化函数&…

解密AWS VPC路由表:显式关联与隐式关联,谁决定了网络出口?

大家好&#xff0c;今天我们来聊一个在 AWS 云计算世界里既基础又关键的话题&#xff1a;VPC 路由表。 很多刚接触 AWS 的朋友&#xff0c;在配置网络时可能会遇到这样的困惑&#xff1a;为什么我的 EC2 实例无法访问互联网&#xff1f;为什么某些子网的网络策略和其他子网不一…

LeetCode题解---<203.移除链表元素>

文章目录题目代码及注释关键点题目 给你一个链表的头节点 head 和一个整数 val &#xff0c;请你删除链表中所有满足 Node.val val 的节点&#xff0c;并返回 新的头节点 。 示例 1&#xff1a; 输入&#xff1a;head [1,2,6,3,4,5,6], val 6 输出&#xff1a;[1,2,3,4,…

【JavaScript高级】构造函数、原型链与数据处理

目录构造函数和原型构造函数实例成员和静态成员构造函数的问题构造函数原型 prototype对象原型 \_\_proto\_\_constructor 构造函数构造函数、实例、原型对象三者之间的关系原型链JavaScript 的成员查找机制&#xff08;规则&#xff09;原型对象的this指向扩展内置对象继承cal…

项目进度与预算脱节,如何进行同步管理

项目进度与预算脱节会导致资源浪费、成本超支和项目延期。进行同步管理的方法包括&#xff1a;建立统一的项目进度预算管理体系、实施实时监控与反馈机制、采用项目管理工具辅助同步管理。尤其是实施实时监控与反馈机制&#xff0c;通过持续监测进度与预算的匹配情况&#xff0…

TCP半关闭

理解TCP半关闭&#xff1a;像水管一样的网络连接控制 从全关闭到半关闭&#xff1a;为什么需要这种机制&#xff1f; 想象你和朋友正在通电话讨论一个重要项目&#xff1a; 全关闭&#xff1a;就像突然挂断电话&#xff0c;双方都无法再说话半关闭&#xff1a;你说"我说完…

衡石科技技术手册--仪表盘过滤控件详解

过滤控件说明 过滤控件 的定义 过滤控件用于在仪表盘中过滤图表数据&#xff0c;分为仪表盘内过滤控件和全局过滤控件。 过滤控件结构说明 字段类型描述uidSTRING过滤控件唯一识别 idappIdLONG过滤控件所属的应用 iddataAppIdLONG字段来源是数据包时的数据包 iddashboar…

ASP.NET Core中数据绑定原理实现详解

在ASP.NET Core 中&#xff0c;数据绑定是将 HTTP 请求中的数据&#xff08;如表单、查询字符串、请求体等&#xff09;映射到控制器动作方法参数或模型对象的过程。以下将从原理、核心组件、执行流程及关键机制等方面详细解析其实现逻辑。 一、数据绑定的核心原理与组件 1. 数…

牛客:HJ24 合唱队[华为机考][最长递增子集][动态规划]

学习要点 求最长递增字列求最长递减子列 题目链接 合唱队_牛客题霸_牛客网 题目描述 解法&#xff1a;动归求最长递增子列 #include <iostream> #include <vector> using namespace std;int main() {int n;while (cin >> n) {// 输入的数组int tmp;vect…

C语言的相关基础概念和常用基本数据类型

1.相关概念变量与常量的定义常量&#xff1a;在程序运行中其值不能改变的量。变量&#xff1a;在程序运行中其值可以改变的量。存储器的区分 RAMROM中文名易失存储器不易失存储器特点掉电丢失数据&#xff0c;但存取快掉电不丢失数据&#xff0c;但存取幔标识符标识符只能…

Spring boot整合dubbo+zookeeper

Spring boot整合dubbozookeeper 下文将简述springboot整合dubbozookeeper实现apiproviderconsumer模式&#xff0c;Api用于定于interface,provider和consumer依赖Api,provider实现api接口&#xff0c;consumer调用provider。 spring boot版本&#xff1a;3.5.3 jdk版本&#xf…

ImportError: /lib/x86_64-linux-gnu/libc.so.6: version GLIBC_2.32‘ not found

简介&#xff1a;在复现 VLM-R1 项目并尝试将其中的 GRPO 算法应用到自己的任务时&#xff0c;按照官方文档配置好环境后&#xff0c;运行过程中遇到了一个非常离谱的错误&#xff1a; ImportError: /lib/x86_64-linux-gnu/libc.so.6: version GLIBC_2.32 not found 这个问题极…

基于Spring Boot的生活用品电商网站的设计与实现

第1章 摘要随着电商行业的飞速发展&#xff0c;生活用品电商网站作为线上购物的一部分&#xff0c;逐渐成为消费者日常购物的重要渠道。为提升网站的管理效率和用户体验&#xff0c;设计并实现了一款基于Spring Boot的生活用品电商网站。该系统通过合理的架构设计&#xff0c;提…

数据结构 单链表(1)

1.概念和结构概念&#xff1a;链表是一种物理存储结构上非连续、非顺序的存储结构&#xff0c;数据元素的逻辑顺序是通过链表中的指针链接次序实现的。通过指针链接次序实现的要怎么理解呢?这是一张链表的结构图:与顺序表不同的是&#xff0c;链表里的每节“车厢” (仔细观察这…

Python爬虫实战:研究PyMongo库相关技术

1. 引言 在当今信息爆炸的时代,互联网上存在着海量的有价值数据。如何高效地获取这些数据并进行存储和分析,成为了数据科学领域的重要研究方向。网络爬虫作为一种自动化的数据采集工具,可以帮助我们从网页中提取所需的信息。而 MongoDB 作为一种流行的 NoSQL 数据库,能够灵…