一,list类的介绍和使用
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来说这可能是一个重要的因素)
2,list类的使用
#include <iostream>
#include <list>
using namespace std;
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;
for (auto e : lt)
{
cout << e << " ";
}
cout << endl;
}
void test_list2()
{
list<int> lt;
lt.push_back(1);
lt.push_back(2);
lt.push_back(3);
lt.push_back(4);
lt.push_back(5);
auto pos = find(lt.begin(), lt.end(), 3);
if (pos != lt.end())
{
//判断pos是否失效?不会
lt.insert(pos, 30);
lt.insert(pos, 30);
lt.insert(pos, 30);
lt.insert(pos, 30);
*pos *= 100;
}
for (auto e : lt)
{
cout << e << " ";
}
cout << endl;
auto post = find(lt.begin(), lt.end(), 4);
if (post != lt.end())
{
lt.erase(pos);
}
for (auto e : lt)
{
cout << e << " ";
}
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);
list<int>::iterator it = lt.begin();
while (it != lt.end())
{
cout << *it << " ";
++it;
}
cout << endl;
lt.remove(3);
for (auto e : lt)
{
cout << e << " ";
}
cout << endl;
}
int main()
{
//test_list1();
//test_list2();
test_list3();
return 0;
}
二,list类的模拟实现
List 的迭代器有两种实现方式,具体应根据容器底层数据结构实现:
1. 原生态指针,比如:vector
2 将原生态指针进行封装,因迭代器使用形式与指针完全相同,因此在自定义的类中必须实现以下方法:
1). 指针可以解引用,迭代器的类中必须重载operator*()
2). 指针可以通过->访问其所指空间成员,迭代器类中必须重载oprator->()
3). 指针可以++向后移动,迭代器类中必须重载operator++()与operator++(int),至于operator--,()/operator--(int)释放需要重载,根据具体的结构来抉择,双向链表可以向前移动,所以需要重载,如果是forward_list就不需要重载--
4). 迭代器需要进行是否相等的比较,因此还需要重载operator==()与operator!=()
#pragma once
#include <iostream>
#include <list>
#include <assert.h>
namespace csy
{
//节点类
template<class T>
struct list_node
{
//节点构造
//若构造结点时未传入数据
//则默认以list容器所存储类型的默认构造函数
//所构造出来的值为传入数据
list_node(const T& x = T())
:_data(x)
, _next(nullptr)
, _prev(nullptr)
{}
//节点成员变量
T _data;
list_node<T>* _next;
list_node<T>* _prev;
};
//迭代器类
template<class T, class Ref, class Ptr>
struct list_iterator
{
//设计三个模板参数,那么就能很好的区分普通迭代器和const迭代器
//迭代器类的模板参数列表当中的Ref和Ptr分别代表的是引用类型和指针类型
typedef list_node<T> Node;
typedef list_iterator<T, Ref, Ptr> iterator;
// 成员变量就只有一个,那就是结点指针
Node* _node;
// 迭代器类实际上就是对结点指针进行了封装,
list_iterator(Node* node)
:_node(node)
{}
// 具有指针类似行为
Ref operator*()
{
return _node->_data;
}
Ptr operator->()
{
return &(operator*());
}
// 迭代器支持比较
bool operator!=(const iterator& it)const
{
return _node != it._node;
}
bool operator==(const iterator& it)const
{
return _node == it._node;
}
// 迭代器支持移动
iterator& operator++()
{
_node = _node->_next;
return *this;
}
iterator operator++(int)
{
iterator temp(*this);
_node = _node->_next;
return temp;
}
iterator& operator--()
{
_node = _node->_prev;
return *this;
}
iterator operator--(int)
{
iterator temp(*this);
_node = _node->_prev;
return temp;
}
};
// list底层是双向带头循环链表
template<class T>
class list
{
public:
typedef list_node<T> Node;
typedef list_iterator<T, T& , T*> iterator;
typedef list_iterator<T,const T& ,const T*> const_iterator;
// 默认成员函数
list()
{
_head = new Node;
_head->_next = _head;
_head->_prev = _head;
}
list(const list<T>& lt)
{
_head = new Node;
_head->_next = _head;
_head->_prev = _head;
//将容器lt当中的数据一个个尾插到新构造的容器后面
for (const auto& e : lt)
{
push_back(e);
}
}
list<T>& operator=(const list<T>& lt)
{
if (this != <) //避免自己给自己赋值
{
clear(); //清空容器
for (const auto& e : lt)
{
//将容器lt当中的数据一个个尾插到链表后面
push_back(e);
}
}
return *this; //支持连续赋值
}
template <class Iterator>
list(Iterator first, Iterator last)
{
_head = new Node;
_head->_prev = _head;
_head->_next = _head;
while (first != last)
{
push_back(*first);
++first;
}
}
~list()
{
clear(); //清理容器
delete _head; //释放头结点
_head = nullptr; //头指针置空
}
// 迭代器相关函数
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 push_back(const T& x)
{
//Node* tail = _head->_prev;
//Node* newnode = new Node(x);
//tail->_next = newnode;
//newnode->_next = _head;
//newnode->_prev = tail;
//_head->_prev = newnode;
insert(end(), x);
}
void pop_back()
{
erase(--end());
}
void push_front(const T& x)
{
insert(begin(), x);
}
void pop_front()
{
erase(begin());
}
iterator insert(iterator pos, const T& x)
{
Node* cur = pos._node;
Node* prev = cur->_prev;
Node* newnode = new Node(x);
// prev new cur
prev->_next = newnode;
newnode->_next = cur;
newnode->_prev = prev;
cur->_prev = newnode;
return iterator(newnode);
}
iterator erase(iterator pos)
{
Node* cur = pos._node;
Node* prev = cur->_prev;
Node* next = cur->_next;
delete cur; //释放cur结点
//建立prev与next之间的双向关系
prev->_next = next;
next->_prev = prev;
//返回pos的下一个位置
return iterator(next);
}
//其他函数
void clear()
{
iterator it = begin();
while (it != end())
{
erase(it);
}
}
size_t size()const
{
Node* cur = _head->_next;
size_t count = 0;
while (cur != _head)
{
count++;
cur = cur->_next;
}
return count;
}
private:
Node* _head;// 指向链表头结点的指针
};
template<class T>
void PrintList(const csy::list<T>& lt)
{
auto it = lt.begin();
while (it != lt.end())
{
cout << *it << " ";
++it;
}
cout << endl;
}
void test_list()
{
// 测试List的构造
list<int> lt;
lt.push_back(1);
lt.push_back(2);
lt.push_back(3);
lt.push_back(4);
lt.push_back(5);
PrintList(lt);
list<int> l2(lt);
PrintList(l2);
list<int> l3 = l2;
PrintList(l3);
int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
list<int> l4(array, array + sizeof(array) / sizeof(array[0]));
PrintList(l4);
// 测试PushBack与PopBack
list<int> l;
l.push_back(1);
l.push_back(2);
l.push_back(3);
PrintList(l);
l.pop_back();
l.pop_back();
PrintList(l);
l.pop_back();
cout << l.size() << endl;
// 测试PushFront与PopFront
l.push_front(1);
l.push_front(2);
l.push_front(3);
PrintList(l);
l.pop_front();
l.pop_front();
PrintList(l);
l.pop_front();
cout << l.size() << endl;
// 测试insert和erase
int arr[] = { 1, 2, 3, 4, 5 };
list<int> ll(arr, arr + sizeof(arr) / sizeof(arr[0]));
auto pos = ll.begin();
ll.insert(ll.begin(), 0);
PrintList(ll);
++pos;
ll.insert(pos, 2);
PrintList(ll);
ll.erase(ll.begin());
ll.erase(pos);
PrintList(ll);
// pos指向的节点已经被删除,pos迭代器失效
cout << *pos << endl;
auto it = ll.begin();
while (it != ll.end())
{
it = ll.erase(it);
}
cout << ll.size() << endl;
}
}