目录
一,关于list
相较于vector线性空间,list就显得复杂许多,它的好处是每次插入或删除一个元素,就配置或释放一个空间,list对于空间的运用有绝对的精准,一点也不浪费。而且,对于任何位置的元素插入或删除,list的时间复杂度永远都是常数
list和vector是两个最常被使用的容器,什么十几下最适合使用哪一种容器,必须视元素的多寡,元素的构造复杂度,元素存取行为的特性而定。
二,list模拟实现
2.1 list节点
//节点
template<class T>
struct list_node
{
list_node(const T& x = T())//T()全缺省
:_data(x)
, _next(nullptr)
, _prev(nullptr)
{}
list_node<T>* _next;
list_node<T>* _prev;
T _data;
};
2.2 list的迭代器类
关于list迭代器有以下几个需要重视的点:
①list不能再像vector那样一样以普通指针作为迭代器,因为其节点不保证在储存空间中连续存在。list迭代器必须又能力指向list的节点,并有能力进行正确的递增,递减,取值,成员存取等操作。所谓“list迭代器正确的递增,递减,取值,成员取用”操作是指,递增时指向下一个节点,递减时指向上一个节点,取值时取的是节点的数据值,成员取用时取用的是节点的成员。
②由于STL库里的list是一个双向链表(double linked_list),迭代器必须具备前移,后移的能力,所以list提供的是 Bidirectional Iterator(双向迭代器)。
③list有一个重要性质:插入操作,删除操作和接合操作都不会造成原有迭代器失效,这在vector中是无法做到的,因为vector的插入操作可能会扩容导致记忆体重新配置,导致原有额迭代器全部失效。
//库里的代码
// typedef __list_iterator<T, T&, T*> iterator;
// typedef __list_iterator<T, const T&, const T*> const_iterator;
//List的迭代器类 -- 像指针一样的类
template<class T, class Ref, class Ptr>//后面两个参数是用来控制迭代器解引用的行为
struct __list_iterator
{
typedef ListNode<T> Node;
typedef __list_iterator<T, Ref, Ptr> iterator;
public:
Node* _node;
__list_iterator(Node* node)
:_node(node)
{}
bool operator!=(const iterator& it)const
{
return _node != it._node;//前面那个是this->_node
}
bool operator==(const iterator& it)const
{
return _node == it._node;
}
//*it会转化成it.operator*(),并且可实现修改
//const T& operator*()
//const T& operator*()
//T& operator*()
Ref operator*()
{
return _node->_data;
}
//T* operator->()
Ptr operator->()
{
return &(operator*());
}
// ++it
iterator& operator++()
{
_node = _node->_next;
return *this;
}
// it++
iterator operator++(int)
{
iterator tmp(*this);
_node = _node->_next;
return tmp;
}
// --it
iterator& operator--()
{
_node = _node->_prev;
return *this;
}
// it--
iterator operator--(int)
{
iterator tmp(*this);
_node = _node->_prev;
return tmp;
}
};
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;
const_iterator begin()const
{
return const_iterator(_head->_next);
}
const_iterator end()const
{
return const_iterator(_head);
}
iterator begin()
{
return iterator(_head->_next);
}
iterator end()
{
return iterator(_head);
}
private:
Node* _head;//定义哨兵
};
2.4 构造和初始化
//构造和初始化
void empty_init()
{
// 创建并初始化哨兵位头结点
_head = new Node;
_head->_next = _head;
_head->_prev = _head;
}
//这里用模板,就是传什么就可以拷贝什么,比如list里面不是int,而是string或者vector
template <class InputIterator>
list(InputIterator first, InputIterator last)//迭代器区间初始化
{
empty_init();
while (first != last)
{
push_back(*first);
++first;
}
}
//构造,带头双向循环链表
list()
{
empty_init();
}
2.5 拷贝和赋值
void swap(list<T>& x)
{
std::swap(_head, x._head);
}
// lt2(lt1) -- 现代写法
list(const list<T>& lt)
{
empty_init();
list<T> tmp(lt.begin(), lt.end());//迭代器区间构造tmp
swap(tmp);
}
// lt1 = lt3
list<T>& operator=(list<T> lt)
{
swap(lt);
return *this;
}
2.6 插入操作函数
2.6.1 insert()
iterator insert(iterator pos, const T& x)
{
Node* cur = pos._node; //创造pos位置的节点对象
Node* prev = cur->_prev; //保存上一个节点的指针
Node* newnode = new Node(x); //造出新节点
// 位置关系 prev newnode cur
prev->_next = newnode;
newnode->_prev = prev;
newnode->_next = cur;
cur->_prev = newnode;
return iterator(newnode);//返回新节点位置的迭代器
}
2.6.2 push_back()
void push_back(const T& x)
{
//Node* tail = _head->_prev;
//Node* newnode = new Node(x);
目前位置关系_head tail newnode
//tail->_next = newnode;
//newnode->_next = _head;
//_head->_prev = newnode;
insert(end(), x);
}
2.6.3 push_front()
void push_front(const T& x)
{
insert(begin(), x);
}
2.7 删除操作函数
2.7.1 erase()
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;
return iterator(next);//由于迭代器失效的问题,删除后返回下一个位置的迭代器
}
2.7.2 pop_back()
void pop_back()
{
erase(--end());
}
2.7.3 pop_front()
void pop_front()
{
erase(begin());
}
2.8 析构函数
void clear()
{
iterator it = begin();
while (it != end())
{
it = erase(it);//erase后it失效了,但是会返回下一个位置的迭代器,我们自己实现的有
}
}
~list()
{
clear();
delete _head;
_head = nullptr;
}
三,完整代码
3.1 list模拟实现
#include <assert.h>
#include<list>
//节点
template<class T>
struct list_node
{
list_node(const T& x = T())
:_data(x)
, _next(nullptr)
, _prev(nullptr)
{}
T _data;
list_node<T>* _next;
list_node<T>* _prev;
};
//库里的代码
// typedef __list_iterator<T, T&, T*> iterator;
// typedef __list_iterator<T, const T&, const T*> const_iterator;
//List的迭代器类 -- 像指针一样的类
template<class T, class Ref, class Ptr>//后面两个参数是用来控制迭代器解引用的行为
struct __list_iterator
{
typedef ListNode<T> Node;
typedef __list_iterator<T, Ref, Ptr> iterator;
public:
Node* _node;
__list_iterator(Node* node)
:_node(node)
{}
bool operator!=(const iterator& it)const
{
return _node != it._node;//前面那个是this->_node
}
bool operator==(const iterator& it)const
{
return _node == it._node;
}
//*it会转化成it.operator*(),并且可实现修改
//const T& operator*()
//const T& operator*()
//T& operator*()
Ref operator*()
{
return _node->_data;
}
//T* operator->()
Ptr operator->()
{
return &(operator*());
}
// ++it
iterator& operator++()
{
_node = _node->_next;
return *this;
}
// it++
iterator operator++(int)
{
iterator tmp(*this);
_node = _node->_next;
return tmp;
}
// --it
iterator& operator--()
{
_node = _node->_prev;
return *this;
}
// it--
iterator operator--(int)
{
iterator 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;
const_iterator begin()const
{
return const_iterator(_head->_next);
}
const_iterator end()const
{
return const_iterator(_head);
}
iterator begin()
{
return iterator(_head->_next);
}
iterator end()
{
return iterator(_head);
}
void empty_init()
{
// 创建并初始化哨兵位头结点
_head = new Node;
_head->_next = _head;
_head->_prev = _head;
}
//构造和初始化
template <class InputIterator>
//这里用模板,就是传什么就可以拷贝什么,比如list里面不是int,而是string或者vector
list(InputIterator first, InputIterator last)
{
empty_init();
while (first != last)
{
push_back(*first);
++first;
}
}
//构造,带头双向循环链表
list()
{
empty_init();
}
void swap(list<T>& x)
{
std::swap(_head, x._head);
}
// lt2(lt1) -- 现代写法
list(const list<T>& lt)
{
empty_init();
list<T> tmp(lt.begin(), lt.end());//迭代器区间构造tmp
swap(tmp);
}
// lt1 = lt3
list<T>& operator=(list<T> lt)
{
swap(lt);
return *this;
}
iterator insert(iterator pos, const T& x)
{
Node* cur = pos._node; //创造pos位置的节点对象
Node* prev = cur->_prev; //保存上一个节点的指针
Node* newnode = new Node(x); //造出新节点
// 位置关系 prev newnode cur
prev->_next = newnode;
newnode->_prev = prev;
newnode->_next = cur;
cur->_prev = newnode;
return iterator(newnode);//返回新节点位置的迭代器
}
~list()
{
clear();
delete _head;
_head = nullptr;
}
void clear()//库里的clear只清数据不清头结点
{
iterator it = begin();
while (it != end())
{
it = erase(it);//erase后it失效了,但是会返回下一个位置的迭代器,我们自己实现的有
}
}
void push_back(const T& x)
{
insert(end(), x);
}
void push_front(const T& x)
{
insert(begin(), x);
}
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;
return iterator(next);//由于迭代器失效的问题,删除后返回下一个位置的迭代器
}
void pop_back()
{
erase(--end());
}
void pop_front()
{
erase(begin());
}
private:
Node* _head;//定义哨兵
};
3.2 测试代码
void test_list1()
{
list<int> lt;
lt.push_back(1);
lt.push_back(2);
lt.push_back(3);
lt.push_back(4);
lt.push_back(5);
//用迭代器遍历链表
list<int>::iterator it = lt.begin();
while (it != lt.end())
{
cout << *it << " ";
++it;
}
cout << endl;
it = lt.begin();
while (it != lt.end())
{
*it *= 2;
++it;
}
for (auto e : lt)
{
cout << e << " ";
}
cout << endl;
}
struct Pos
{
int _a1;
int _a2;
Pos(int a1 = 0, int a2 = 0)
:_a1(a1)
, _a2(a2)
{}
};
//->
void test_list2()
{
int x = 10;
int* p1 = &x;
cout << *p1 << endl;
Pos aa;
Pos* p2 = &aa;
p2->_a1;
p2->_a2;
list<Pos> lt;
lt.push_back(Pos(10, 20));
lt.push_back(Pos(10, 21));
list<Pos>::iterator it = lt.begin();
while (it != lt.end())
{
//cout << (*it)._a1 << " " << (*it)._a2 << endl;//这个访问方式不爽,可以直接用箭头去访问
cout << it->_a1 << ":" << it->_a2 << endl;
//->咋调用的呢?//看板书
++it;
}
cout << endl;
}
void Func(const list<int>& l)//用了&就可以加const
{
//list<int>::iterator it = l.begin();//报错,权限放大
list<int>::const_iterator it = l.begin();//const迭代器
while (it != l.end())
{
//*it = 10;const不能修改
cout << *it << " ";
++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_back(5);
Func(lt);
}
void test_list4()
{
list<int> lt;
lt.push_back(1);
lt.push_back(2);
lt.push_back(3);
lt.push_back(4);
lt.push_back(5);
list<int>::iterator it = lt.begin();
while (it != lt.end())
{
cout << *it << " ";
++it;
}
cout << endl;
lt.push_front(10);
lt.push_front(20);
lt.push_front(30);
lt.push_front(40);
lt.pop_back();
lt.pop_back();
lt.pop_front();
for (auto e : lt)
{
cout << e << " ";
}
cout << endl;
auto pos = find(lt.begin(), lt.end(), 3);
if (pos != lt.end())
{
// pos是否会失效?不会
lt.insert(pos, 30);
//lt.insert(pos, 30);
*pos *= 100;
}
for (auto e : lt)
{
cout << e << " ";
}
cout << endl;
}
void test_list5()
{
list<int> lt;
lt.push_back(1);
lt.push_back(2);
lt.push_back(3);
lt.push_back(4);
lt.push_back(5);
list<int> copy = lt;
for (auto& e : lt)
{
e *= 2;
}
cout << endl;
for (auto e : copy)
{
cout << e << " ";
}
cout << endl;
for (auto e : lt)
{
cout << e << " ";
}
cout << endl;
//lt.clear();
list<int> lt1;
lt1.push_back(10);
lt1.push_back(20);
lt1.push_back(30);
copy = lt1;
for (auto e : copy)
{
cout << e << " ";
}
cout << endl;
for (auto e : lt1)
{
cout << e << " ";
}
cout << endl;
}
void test_list6()
{
list<int> lt;
lt.push_back(1);
lt.push_back(2);
lt.push_back(3);
lt.push_back(4);
lt.push_back(5);
list<int> lt2(lt);
}