要努力,但不要着急,繁花锦簇,硕果累累都需要过程!
目录
1.list介绍及使用
1.1list介绍:
1. list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。
2. list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。
3.list最大的缺陷是不支持
任意位置
的随机访问
1.2list的使用:
1.2.1list的构造:
list()
|
构造空的list
|
list (size_type n, const value_type& val = value_type())
|
构造的list中包含n个值为val的元素
|
list (InputIterator fifirst, InputIterator last)
|
用[first, last)区间中的元素构造list
|
list (const list& x)
|
拷贝构造函数
|
1.2.2list iterator的使用:
begin()+end() |
返回第一个元素的迭代器+返回最后一个元素下一个位置的迭代器
|
rebegin+rend() |
返回第一个元素的reverse_iterator,即end位置,返回最后一个元素下一个位置的
reverse_iterator,即begin位置
|
注:
1. begin与end为正向迭代器,对迭代器执行++操作,迭代器向后移动
2. rbegin(end)与rend(begin)为反向迭代器,对迭代器执行++操作,迭代器向前移动
1.2.3list modify:
push_back
|
在list尾部插入值为val的元素
|
pop_back
|
删除list中最后一个元素
|
insert
|
在list position 位置中插入值为val的元素
|
erase
|
删除list position位置的元素
|
swap
|
交换两个list中的元素
|
clear
|
清空list中的有效元素
|
push_front
|
在list首元素前插入值为val的元素
|
pop_front
|
删除list中第一个元素
|
1.2.4list capacity:
empty |
检测list是否为空,是返回true,否则返回false
|
size |
返回list中有效节点的个数
|
1.2.5operatoin:
remove | 删除指定元素 |
sort | 对数据进行排序 |
unique | 去掉重复元素的数据 |
注:list不能使用算法库里面的sort
原因:
list底层使用的是双向链表的方式,sort底层在实现的时候使用了指针-指针的方式,而list不能通过指针-指针的方式得到中间元素的个数
2.list的模拟实现
#include<iostream> #include<assert.h> using namespace std; namespace lt { template<typename T> struct list_node { list_node* _next; list_node* _prev; T _data; list_node(const T& val) :_next(nullptr), _prev(nullptr), _data(val) {}; }; //template<typename T> //struct __list_iterator //{ // typedef list_node<T> node; // node* _pnode; // __list_iterator(node* p) // :_pnode(p) // {} // T& operator*() // { // return _pnode->_data; // } // __list_iterator<T>& operator++() // { // _pnode = _pnode->_next; // return *this; // } // __list_iterator<T> operator--() // { // _pnode = _pnode->_prev; // return *this; // } // bool operator!=(const __list_iterator<T>& it) // { // return _pnode != it._pnode; // } //}; //template<typename T> //struct __list_const_iterator //{ // typedef list_node<T> node; // node* _pnode; // __list_const_iterator(node* p) // :_pnode(p) // {} // const T& operator*() // { // return _pnode->_data; // } // __list_const_iterator<T>& operator++() // { // _pnode = _pnode->_next; // return *this; // } // __list_const_iterator<T> operator--() // { // _pnode = _pnode->_prev; // return *this; // } // bool operator!=(const __list_const_iterator<T>& it) // { // return _pnode != it._pnode; // } //}; template<typename T, typename ref, typename ptr> struct __list_iterator { typedef list_node<T> node; typedef __list_iterator<T, ref, ptr> self; node* _pnode; __list_iterator(node* p) :_pnode(p) {} ref& operator*() { return _pnode->_data; } self& operator++() { _pnode = _pnode->_next; return *this; } self operator++(int) { self tmp(*this); _pnode = _pnode->_next; return tmp; } self& operator--() { _pnode = _pnode->_prev; return *this; } self operator--(int) { self tmp(*this); _pnode = _pnode->_prev; return tmp; } ptr operator->() { return &_pnode->_data; } bool operator!=(const self& it)const { return _pnode != it._pnode; } }; template <typename 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&> iterator; //typedef __list_iterator<T, const T&> const_iterator; typedef __list_iterator<T, T&, T*> iterator; typedef __list_iterator<T, const T&, const T*> const_iterator; iterator begin() { return iterator(_head->_next); } iterator end() { return iterator(_head); } const_iterator begin() const { return const_iterator(_head->_next); } const_iterator end() const { return const_iterator(_head); } void empty_initalize() { _head = new node(T()); _head->_next = _head; _head->_prev = _head; } list() { empty_initalize(); } //传统写法 //list(const list<T>& lt) //{ // empty_initalize(); // for (auto& e : lt) // { // push_back(e); // } //} template <class InputIterator> list(InputIterator first, InputIterator last) { empty_initalize(); while (first != last) { push_back(*first); ++first; } } void swap(list<T>& lt) { std::swap(_head, lt._head); std::swap(_size, lt._size); } //拷贝构造现代写法: list(const list<T>& lt) { empty_initalize(); list<T> tmp(lt.begin(), lt.end()); swap(tmp); } //list<T>& operator=(const list<T>& lt) //{ // if (this != <) // { // clear(); // for (auto& e : lt) // { // push_back(e); // } // } // return *this; //} //赋值重载现代写法: list<T>& operator=(list<T> lt) { swap(lt); return *this; } ~list() { clear(); delete _head; _head = nullptr; } void clear() { iterator it = begin(); while (it != end()) { it = erase(it); } } void push_back(const T& val) { insert(end(), val); } void push_front(const T& val) { insert(begin(), val); } void pop_back() { erase(--end()); --_size; } void pop_front() { erase(begin()); } size_t size() const { return _size; } bool empty()const { return _size == 0; } iterator insert(iterator pos, const T& val) { node* newnode = new node(val); node* cur = pos._pnode; node* prev = cur->_prev; prev->_next = newnode; newnode->_prev = prev; newnode->_next = cur; cur->_prev = newnode; _size++; return iterator(newnode); } iterator erase(iterator pos) { assert(pos != end()); node* prev = pos._pnode->_prev; node* next = pos._pnode->_next; prev->_next = next; next->_prev = prev; delete pos._pnode; _size--; return iterator(next); } private: node* _head; size_t _size; };
3.list与vector的区别
vector | list | |
底层结构 |
动态顺序表,一段连续空间
|
带头结点的双向循环链表
|
随机访问 |
支持随机访问,访问某个元素效率O(1)
|
不支持随机访问,访问某个元素
效率O(N)
|
插入和删除 |
任意位置插入和删除效率低,需要搬移元素,时间复杂
度为O(N),插入时有可能需要增容,增容:开辟新空
间,拷贝元素,释放旧空间,导致效率更低
|
任意位置插入和删除效率高,不
需要搬移元素,时间复杂度为
O(1)
|
空间利用率 |
底层为连续空间,不容易造成内存碎片,空间利用率
高,缓存利用率高
|
底层节点动态开辟,小节点容易 造成内存碎片,空间利用率低, 缓存利用率低
|
迭代器 |
原生态指针
|
对原生态指针(节点指针)进行封装
|
迭代器失效 |
在插入元素时,要给所有的迭代器重新赋值,因为插入元素有可能会导致重新扩容,致使原来迭代器失效,删除时,当前迭代器需要重新赋值否则会失效
|
插入元素不会导致迭代器失效,删除元素时,只会导致当前迭代器失效,其他迭代器不受影响
|
使用场景 |
需要高效存储,支持随机访问,不关心插入删除效率
|
大量插入和删除操作,不关心随 机访问
|