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
英文地址,請注明出處:http://en.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 數據庫,能夠靈…