目录
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
2.1.1list节点
2.1.2list常见功能接口
2.1.3list迭代器实现
2.1.4list构造与析构函数
2.1.5完整代码
2.2 list的反向迭代器
3. list与vector的对比
1. list的介绍及使用
1.1 list的介绍
list的文档介绍
在数据结构当中,我们学习过链表的一系列形式,带头、不带头、双向、单向、循环、不循环等形式,其中带头双向链表由于可以轻易找到头尾节点,某一节点前后节点,具有头结点,因此链表为空不需要做特殊处理等优势,作为链表最完善的形式。C++STL中list底层的结构就是采用带头双向循环链表(对list的明白需要创建在对数据结构有一定基础上,对于链表不了解的读者可以先移步学习链表。)
1.2 list的使用
list中的接口比力多,此处类似之前string、vector,只需要掌握如何正确的使用,然后再去深入研究背后的原理,以达到可扩展的本领。以下为list中一些常见的重要接口。
1.2.1 list的构造
构造函数( (constructor))接口说明
listlist (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- // list的构造
- void TestList1()
- {
- list<int> l1; // 构造空的l1
- list<int> l2(4, 100); // l2中放4个值为100的元素
- list<int> l3(l2.begin(), l2.end()); // 用l2的[begin(), end())左闭右开的区间构造l3
- list<int> l4(l3); // 用l3拷贝构造l4
- // 以数组为迭代器区间构造l5
- int array[] = { 16,2,77,29 };
- list<int> l5(array, array + sizeof(array) / sizeof(int));
- // 列表格式初始化C++11
- list<int> l6{ 1,2,3,4,5 };
- // 用迭代器方式打印l5中的元素
- list<int>::iterator it = l5.begin();
- while (it != l5.end())
- {
- cout << *it << " ";
- ++it;
- }
- cout << endl;
- // C++11范围for的方式遍历
- for (auto& e : l5)
- cout << e << " ";
- cout << endl;
- }
复制代码 1.2.2 list iterator的使用
此处,各人可临时将迭代器明白成一个指针,该指针指向list中的某个节点。当然由于链表的节点存储并不是一块连续的空间,因此list的迭代器并不是原生指针,而是通过封装实现的。
函数声明接口说明begin + end返回第一个元素的迭代器+返回最后一个元素下一个位置的迭代器rbegin
+rend返回第一个元素的reverse_iterator,即end位置,返回最后一个元素下一个位置的reverse_iterator,即begin位置
- // list迭代器的使用
- // 注意:遍历链表只能用迭代器和范围for
- void PrintList(const list<int>& l)
- {
- // 注意这里调用的是list的 begin() const,返回list的const_iterator对象
- for (list<int>::const_iterator it = l.begin(); it != l.end(); ++it)
- {
- cout << *it << " ";
- // *it = 10; 编译不通过
- }
- cout << endl;
- }
- void TestList2()
- {
- int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
- list<int> l(array, array + sizeof(array) / sizeof(array[0]));
- // 使用正向迭代器正向list中的元素
- // list<int>::iterator it = l.begin(); // C++98中语法
- auto it = l.begin(); // C++11之后推荐写法
- while (it != l.end())
- {
- cout << *it << " ";
- ++it;
- }
- cout << endl;
- // 使用反向迭代器逆向打印list中的元素
- // list<int>::reverse_iterator rit = l.rbegin();
- auto rit = l.rbegin();
- while (rit != l.rend())
- {
- cout << *rit << " ";
- ++rit;
- }
- cout << endl;
- }
复制代码 STL中范围同一都是左闭右开的区间,在list中由于头结点并不存储有效的数据,begin返回的是指向第一个有效数据的迭代器,end()返回最后一个元素的下一个位置,由于是循环链表,最后一个元素的下一个位置指向就是头结点。
list由于底层的链表存储空间不连续,因此list不在支持下标 +[]的随机访问,同样,比起之前string与vector,list的迭代器也发生了变化,list迭代器不再支持+或-某一常数来改变访问的指向。
这里我们需要在拓展增补一下迭代器的相干概念
基于功能上是正向还是反向遍历,迭代器可以分为正向迭代器iterator与反向迭代器reverse_iterator,以及支持const对象的迭代器。
基于底层结构的不同,实现出来的迭代器又有性质上的不同,可以分为单向、双向、随机迭代器(STL底层还抽象出一个最小单元的输入迭代器,我们使用的只有上诉三个迭代器,这个最小单元可以不考虑),不同迭代器支持的迭代操作不同,单向迭代器只支持单向移动,只能++,双向迭代器如我们本次学习list支持++、--两个方向迭代,而随机迭代器支持通过+、-某一个对象跳跃式移动到某一个位置。STL中所实现的一些组件,由于底层实现存在+、-、++、--等操作,对于有的迭代器是不支持的,如上段代码中sort底层实现式快排加堆排存在+、-等操作,因此传入的迭代器必须是随机迭代器。(不同的迭代器之间其实还存在者继承等复杂关系,本文不在深入探究)
由上图不同迭代器支持的符号,我们可以得出使用范围上随机迭代器>双向迭代器>单向迭代器。以是在日后的使用中,我们需要根据文档查询对应支持的迭代器范例。
【留意】
1. begin与end为正向迭代器,对迭代器执行++操作,迭代器向后移动
2. rbegin(end)与rend(begin)为反向迭代器,对迭代器执行++操作,迭代器向前移动
1.2.3 list capacity
函数声明接口说明empty检测list是否为空,是返回true,否则返回falsesize返回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插入和删除
- // push_back/pop_back/push_front/pop_front
- void TestList3()
- {
- int array[] = { 1, 2, 3 };
- list<int> L(array, array + sizeof(array) / sizeof(array[0]));
- // 在list的尾部插入4,头部插入0
- L.push_back(4);
- L.push_front(0);
- PrintList(L);
- // 删除list尾部节点和头部节点
- L.pop_back();
- L.pop_front();
- PrintList(L);
- }
- // insert /erase
- void TestList4()
- {
- int array1[] = { 1, 2, 3 };
- list<int> L(array1, array1 + sizeof(array1) / sizeof(array1[0]));
- // 获取链表中第二个节点
- auto pos = ++L.begin();
- cout << *pos << endl;
- // 在pos前插入值为4的元素
- L.insert(pos, 4);
- PrintList(L);
- // 在pos前插入5个值为5的元素
- L.insert(pos, 5, 5);
- PrintList(L);
- // 在pos前插入[v.begin(), v.end)区间中的元素
- vector<int> v{ 7, 8, 9 };
- L.insert(pos, v.begin(), v.end());
- PrintList(L);
- // 删除pos位置上的元素
- L.erase(pos);
- PrintList(L);
- // 删除list中[begin, end)区间中的元素,即删除list中的所有元素
- L.erase(L.begin(), L.end());
- PrintList(L);
- }
- // resize/swap/clear
- void TestList5()
- {
- // 用数组来构造list
- int array1[] = { 1, 2, 3 };
- list<int> l1(array1, array1 + sizeof(array1) / sizeof(array1[0]));
- PrintList(l1);
- // 交换l1和l2中的元素
- list<int> l2;
- l1.swap(l2);
- PrintList(l1);
- PrintList(l2);
- // 将l2中的元素清空
- l2.clear();
- cout << l2.size() << endl;
- }
复制代码 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++); // it = l.erase(it);erase会返回当前删除节点的下一节点
- }
- }
复制代码 2. list的模拟实现
2.1 模拟实现list
要模拟实现list,必须要熟悉list的底层结构以及其接口的含义,通过上面的学习,这些内容已基本
掌握,现在我们来模拟实现list。
2.1.1list节点
- //链表的节点,由于存储的数据不定,我们这里实现成模板
- template<class T>
- struct list_node
- {
- T _data;
- list_node<T>* _next;
- list_node<T>* _prev;
- list_node(const T& data = T())
- :_data(data)
- ,_next(nullptr)
- ,_prev(nullptr)
- {}
- };
复制代码 2.1.2list常见功能接口
- void clear()
- {
- auto it = begin();//挨个释放list中节点资源
- while (it != end())
- {
- it = erase(it);//复用删除功能
- }
- }
- void swap(list<T>& lt)
- {
- std::swap(_head, lt._head);
- std::swap(_size, lt._size);
- }
- void push_back(const T& x)
- {
- /*Node* newnode = new Node(x);
- Node* tail = _head->_prev;
- tail->_next = newnode;
- newnode->_prev = tail;
- newnode->_next = _head;
- _head->_prev = newnode;
- ++_size;*/
- insert(end(), x);//尾插直接复用插入代码
- }
- void push_front(const T& x)
- {
- insert(begin(), x);//头插直接复用插入代码
- }
- iterator insert(iterator pos, const T& x)
- {
- //插入一个新节点
- Node* cur = pos._node;//当前位置节点
- Node* prev = cur->_prev;//前驱节点
- Node* newnode = new Node(x);
- // prev newnode cur
- newnode->_next = cur;//新节点next指向当前位置节点
- cur->_prev = newnode;//当前节点前驱指针指向新节点
- newnode->_prev = prev;//新前驱节点的前驱指针指向前驱节点
- prev->_next = newnode;//前驱节点next指向新节点
- ++_size;//更新list中节点个数
- return newnode;//返回新节点指针,返回值在根据指针构造出对应迭代器
- }
- void pop_back()
- {
- erase(--end());//尾删直接复用对应删除代码
- }
- void pop_front()
- {
- erase(begin());//前删直接复用对应删除代码
- }
- iterator erase(iterator pos)
- {
- assert(pos != end());//不能删除头结点
- Node* prev = pos._node->_prev;//将删除节点前驱跟后驱节点的指向相连
- Node* next = pos._node->_next;
- prev->_next = next;
- next->_prev = prev;
- delete pos._node;//释放删除节点的资源
- --_size;
- return next;//返回删除节点后驱节点指针,返回值在根据指针构造出对应迭代器
- //这一步返回操作可以更新外部指向删除节点的迭代器的值
- //防止迭代器失效的问题
- }
- size_t size() const
- {
- return _size;
- }
- bool empty() const
- {
- return _size == 0;
- }
-
复制代码
2.1.3list迭代器实现
由于list的底层是链表,存储空间并不连续,因此,我们需要利用模板举行封装。首先需要说明的是,由于const_iterator指向的对象不能修改,因此如果我们通过重载的函数返回引用或者指针,那么针对const_iterator跟iterator,我们就需要写两份非常相似的代码,非常冗余,对此库内里增长Ref与Ptr两个模板参数用来控制返回值中的引用与指针,传入的参数是const对像,函数返回的引用与指针就是const修饰的,如果是平凡对象,就是平凡的指针和引用,我们就不再需要写两份非常相似的代码了。
因为list的迭代器,我们无法通过原生指针实现,为了能过还原对应的指针操作,我们需要在迭代器类中有一个成员变量是节点指针,同时由于迭代器的相干操作经常使用,我们这里使用struct定义类。
2.1.4list构造与析构函数
与之前string和vector实现不同,空list中构造出来是有一个头结点,头节点的前驱和后驱指针都指向自己。因此,我们这里要单独实现一个空初始化函数。
- void empty_init()
- {
- _head = new Node;
- _head->_next = _head;
- _head->_prev = _head;
- _size = 0;
- }
- list()
- {
- empty_init();
- }
- list(initializer_list<T> il)
- {
- empty_init();
- for (auto& e : il)
- {
- push_back(e);
- }
- }
- // lt2(lt1)
- list(const list<T>& lt)
- {
- empty_init();
- for (auto& e : lt)
- {
- push_back(e);
- }
- }
- // lt1 = lt3 现代写法的赋值重载
- list<T>& operator=(list<T> lt)
- {
- swap(lt);
- return *this;
- }
- ~list()
- {
- clear();
- delete _head;
- _head = nullptr;
- }
复制代码 2.1.5完整代码
- #pragma once
- #include<assert.h>
- namespace zlr
- {
- template<class T>
- struct list_node//链表的节点
- {
- T _data;
- list_node<T>* _next;
- list_node<T>* _prev;
- list_node(const T& data = T())
- :_data(data)
- ,_next(nullptr)
- ,_prev(nullptr)
- {}
- };
- template<class T, class Ref, class Ptr>
- struct list_iterator
- {
- typedef list_node<T> Node;
- typedef list_iterator<T, Ref, Ptr> Self;//通过模板参数控制iterator与const_iterator
- //不同返回值
- Node* _node;
- list_iterator(Node* node)
- :_node(node)
- {}
- Ref operator*()
- {
- return _node->_data;
- }
- Ptr operator->()
- {
- return &_node->_data;
- }
- 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;
- }
-
- bool operator!=(const Self& s) const
- {
- return _node != s._node;
- }
- bool operator==(const Self& s) const
- {
- return _node == s._node;
- }
- };
- /*template<class T>//如果不通过函模板参数控制,我们就需要因为const_iterator多写一份非常相
- //似的代码
- struct list_const_iterator
- {
- typedef list_node<T> Node;
- typedef list_const_iterator<T> Self;
- Node* _node;
- list_const_iterator(Node* node)
- :_node(node)
- {}
- const T& operator*()
- {
- return _node->_data;
- }
- const T* operator->()
- {
- return &_node->_data;
- }
- 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;
- }
- bool operator!=(const Self& s) const
- {
- return _node != s._node;
- }
- bool operator==(const Self& s) const
- {
- return _node == s._node;
- }
- };*/
- template<class T>
- class list
- {
- typedef list_node<T> Node;
- public:
- /*typedef list_iterator<T> iterator;
- typedef list_const_iterator<T> const_iterator;*/
- typedef list_iterator<T, T&, T*> iterator;//将类型重新封装,便于使用,统一风格
- typedef list_iterator<T, const T&, const T*> const_iterator;
- iterator begin()
- {
- /* iterator it(_head->_next);
- return it;*/
- //return iterator(_head->_next);
- return _head->_next;
- }
- iterator end()
- {
- return _head;
- }
- const_iterator begin() const
- {
- return _head->_next;
- }
- const_iterator end() const
- {
- return _head;
- }
- void empty_init()
- {
- _head = new Node;
- _head->_next = _head;
- _head->_prev = _head;
- _size = 0;
- }
- list()
- {
- empty_init();
- }
- list(initializer_list<T> il)
- {
- empty_init();
- for (auto& e : il)
- {
- push_back(e);
- }
- }
- // lt2(lt1)
- list(const list<T>& lt)
- {
- empty_init();
- for (auto& e : lt)
- {
- push_back(e);
- }
- }
- // lt1 = lt3
- list<T>& operator=(list<T> lt)
- {
- swap(lt);
- return *this;
- }
- ~list()
- {
- clear();
- delete _head;
- _head = nullptr;
- }
- void clear()
- {
- auto it = begin();
- while (it != end())
- {
- it = erase(it);
- }
- }
- void swap(list<T>& lt)
- {
- std::swap(_head, lt._head);
- std::swap(_size, lt._size);
- }
- void push_back(const T& x)
- {
- /*Node* newnode = new Node(x);
- Node* tail = _head->_prev;
- tail->_next = newnode;
- newnode->_prev = tail;
- newnode->_next = _head;
- _head->_prev = newnode;
- ++_size;*/
- insert(end(), x);//直接复用代码
- }
- void push_front(const T& x)
- {
- insert(begin(), x);
- }
- iterator insert(iterator pos, const T& x)
- {
- Node* cur = pos._node;
- Node* prev = cur->_prev;
- Node* newnode = new Node(x);
- // prev newnode cur
- newnode->_next = cur;
- cur->_prev = newnode;
- newnode->_prev = prev;
- prev->_next = newnode;
- ++_size;
- return newnode;
- }
- void pop_back()
- {
- erase(--end());
- }
- void pop_front()
- {
- erase(begin());
- }
- iterator erase(iterator pos)
- {
- assert(pos != end());
- Node* prev = pos._node->_prev;
- Node* next = pos._node->_next;
- prev->_next = next;
- next->_prev = prev;
- delete pos._node;
- --_size;
- return next;
- }
- size_t size() const
- {
- return _size;
- }
- bool empty() const
- {
- return _size == 0;
- }
- private:
- Node* _head;
- size_t _size;
- };
- struct AA
- {
- int _a1 = 1;
- int _a2 = 1;
- };
- // 按需实例化
- // T* const ptr1
- // const T* ptr2
- template<class Container>
- void print_container(const Container& con)
- {
- // const iterator -> 迭代器本身不能修改
- // const_iterator -> 指向内容不能修改
- typename Container::const_iterator it = con.begin();
- //auto it = con.begin();
- while (it != con.end())
- {
- //*it += 10;
- cout << *it << " ";
- ++it;
- }
- cout << endl;
- for (auto e : con)
- {
- cout << e << " ";
- }
- 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 += 10;
- cout << *it << " ";
- ++it;
- }
- cout << endl;
- for (auto e : lt)
- {
- cout << e << " ";
- }
- cout << endl;
- print_container(lt);
- list<AA> lta;
- lta.push_back(AA());
- lta.push_back(AA());
- lta.push_back(AA());
- lta.push_back(AA());
- list<AA>::iterator ita = lta.begin();
- while (ita != lta.end())
- {
- //cout << (*ita)._a1 << ":" << (*ita)._a2 << endl;
- // 特殊处理,本来应该是两个->才合理,为了可读性,省略了一个->
- cout << ita->_a1 << ":" << ita->_a2 << endl;
- cout << ita.operator->()->_a1 << ":" << ita.operator->()->_a2 << endl;
- ++ita;
- }
- cout << endl;
- }
- void test_list2()
- {
- list<int> lt;
- lt.push_back(1);
- lt.push_back(2);
- lt.push_back(3);
- lt.push_back(4);
- // insert以后迭代器不失效
- list<int>::iterator it = lt.begin();
- lt.insert(it, 10);
- *it += 100;
- print_container(lt);
- // erase以后迭代器失效
- // 删除所有的偶数
- it = lt.begin();
- while (it != lt.end())
- {
- if (*it % 2 == 0)
- {
- it = lt.erase(it);
- }
- else
- {
- ++it;
- }
- }
- print_container(lt);
- }
- void test_list3()
- {
- list<int> lt1;
- lt1.push_back(1);
- lt1.push_back(2);
- lt1.push_back(3);
- lt1.push_back(4);
- list<int> lt2(lt1);
- print_container(lt1);
- print_container(lt2);
- list<int> lt3;
- lt3.push_back(10);
- lt3.push_back(20);
- lt3.push_back(30);
- lt3.push_back(40);
- lt1 = lt3;
- print_container(lt1);
- print_container(lt3);
- }
- void func(const list<int>& lt)
- {
- print_container(lt);
- }
- void test_list4()
- {
- // 直接构造
- list<int> lt0({ 1,2,3,4,5,6 });
- // 隐式类型转换
- list<int> lt1 = { 1,2,3,4,5,6,7,8 };
- const list<int>& lt3 = { 1,2,3,4,5,6,7,8 };
- func(lt0);
- func({ 1,2,3,4,5,6 });
- print_container(lt1);
-
- //auto il = { 10, 20, 30 };
- /* initializer_list<int> il = { 10, 20, 30 };
- cout << typeid(il).name() << endl;
- cout << sizeof(il) << 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中非常重要的序列式容器,由于两个容器的底层结构不同,导致其特性以及
应用场景不同,其重要不同如下:(vector与list的重要区别还是基于底层顺序表与链表的区别,对区别感兴趣的读者可以移步看笔者【初阶数据结构】顺序表与链表的比力(附题)这篇文章)
vectorlist底
层
结
构动态顺序表,一段连续空间带头结点的双向循环链表随
机
访
问支持随机访问,访问某个元素效率O(1)不支持随机访问,访问某个元素效率O(N)插
入
和
删
除任意位置插入和删除效率低,需要搬移元素,时间复杂度为O(N),插入时有大概需要增容,增容:开辟新空间,拷贝元素,开释旧空间,导致效率更低任意位置插入和删除效率高,不需要搬移元素,时间复杂度为O(1)空
间
利
用
率底层为连续空间,不轻易造成内存碎片,空间利用率高,缓存利用率高底层节点动态开辟,小节点轻易造成内存碎片,空间利用率低,缓存利用率低迭
代
器原生态指针对原生态指针(节点指针)举行封装迭
代
器
失
效在插入元素时,要给全部的迭代器重新赋值,因为插入元素有大概会导致重新扩容,致使原来迭代器失效,删除时,当前迭代器需要重新赋值否则会失效插入元素不会导致迭代器失效,删除元素时,只会导致当前迭代器失效,其他迭代器不受影响使
用
场
景需要高效存储,支持随机访问,不关心插入删除效率大量插入和删除操作,不关心随机访问
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |