list容器概述:链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通 过链表中的指针链接次序实现的。list是一个双向循环链表
具体和这个图差不多
文章目录
- 一.list的基本API
- 二.list的使用
- 三.list的模拟实现
一、list的基本API
3.6.4.1 list 构造函数
list<T> lstT;//list 采用采用模板类实现,对象的默认构造形式:
list(beg,end);//构造函数将[beg, end)区间中的元素拷贝给本身。
list(n,elem);//构造函数将 n 个 elem 拷贝给本身。
list(const list &lst);//拷贝构造函数。
3.6.4.2 list 数据元素插入和删除操作
push_back(elem);//在容器尾部加入一个元素
pop_back();//删除容器中最后一个元素
push_front(elem);//在容器开头插入一个元素
pop_front();//从容器开头移除第一个元素
insert(pos,elem);//在 pos 位置插 elem 元素的拷贝,返回新数据的位置。
insert(pos,n,elem);//在 pos 位置插入 n 个 elem 数据,无返回值。
insert(pos,beg,end);//在 pos 位置插入[beg,end)区间的数据,无返回值。
clear();//移除容器的所有数据
erase(beg,end);//删除[beg,end)区间的数据,返回下一个数据的位置。
erase(pos);//删除 pos 位置的数据,返回下一个数据的位置。
remove(elem);//删除容器中所有与 elem 值匹配的元素。
3.6.4.3 list 大小操作
size();//返回容器中元素的个数
empty();//判断容器是否为空
resize(num);//重新指定容器的长度为 num,
若容器变长,则以默认值填充新位置。
如果容器变短,则末尾超出容器长度的元素被删除。
resize(num, elem);//重新指定容器的长度为 num,
若容器变长,则以 elem 值填充新位置。
如果容器变短,则末尾超出容器长度的元素被删除。
3.6.4.4 list 赋值操作
assign(beg, end);//将[beg, end)区间中的数据拷贝赋值给本身。
assign(n, elem);//将 n 个 elem 拷贝赋值给本身。
list& operator=(const list &lst);//重载等号操作符
swap(lst);//将 lst 与本身的元素互换。
3.6.4.5 list 数据的存取
front();//返回第一个元素。
back();//返回最后一个元素。
3.6.4.6 list 反转排序
reverse();//反转链表,比如 lst 包含 1,3,5 元素,运行此方法后,lst 就包含 5,3,1
元素。
sort(); //list 排序
3.6.4.6 list 反转排序
reverse();//反转链表,比如 lst 包含 1,3,5 元素,运行此方法后,lst 就包含 5,3,1
元素。
sort(); //list 排序
二、常见API的使用
#include<iostream>
#include<list>
using namespace std;
int main()
{
list<int> lt;
lt.push_back(10);
lt.push_back(20);
lt.push_back(30);
lt.push_back(40);
lt.push_back(50);
lt.push_back(10);
list<int>::iterator it = lt.begin();
while (it != lt.end())
{
cout << *it;
++it;
cout << endl;
}
cout << endl;
system("pause");
return 0;
}
三.list的模拟及其实现
#pragma once
#include<assert.h>
namespace zdc
{
template<class T>
struct list_node
{
T _data;
list_node<T>* _next;//节点后指针
list_node<T>* _prev;//指向前面的指针
list_node(const T& x = T())
:_data(x)
, _next(nullptr)
, _prev(nullptr)
{}
};
template<class T, class Ref, class Ptr>//用于控制迭代器对象是看不是constduixiang
struct __list_iterator//实现迭代器
{
typedef list_node<T> Node;//结构体指针
typedef __list_iterator<T, Ref, Ptr> iterator;//普通迭代器T引用
//typedef bidirectional_iterator_tag iterator_category;
//typedef T value_type;
//typedef Ptr pointer;
//typedef Ref reference;
//typedef ptrdiff_t difference_type;
//
Node* _node;//
__list_iterator(Node*node)//用这个指针来构造
:_node(node)
{}
bool operator !=(const iterator& it)const
{
return _node != it._node;//不等于比大小可以用指针来比
}
bool operator==(const iterator& it) const
{
return _node == it._node;
}
//*it就是返回it里的数据可以都或者xie
Ref operator*()
{
return _node->_data;//引用返回可以修改
}
Ptr operator->()//用模板参数控制迭代器类型
{
return &(operator*());//这个实际胜率了一个-》Node*->it->
}
iterator& operator++()
{
_node = _node->_next;//所谓++就是指向下一个位置it=——node
return *this;
}
iterator& operator++(int)
{
iterator tmp(*this);
_node = _node->_next;
return tmp;
}
iterator& operator--()
{
_node = _node->_prev;
return *this;
}
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;
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);
}
list()
{
// _head = new Node;//开辟新节点不需要存储数据
// _head->_next = _head;
// _head->_prev = _head;//形成循环链表
empty_init();
}
void empty_init()
{
_head = new Node;//开辟新节点不需要存储数据
_head->_next = _head;
_head->_prev = _head;//形成循环链表
//创建并初始化头结点
}
template <class InputIterator>
list(InputIterator first, InputIterator last)
{
empty_init();//先初始化
while (first != last)//相当与begin !=end
{
push_back(*first);//取数据逐渐尾插
++first;//其实就是便利数据然后尾插
}
}
list<T>& operator=(list<T> it)//赋值
{
swap(it);
return *this;
}
void swap(list<T> &tmp)
{
std::swap(_head, tmp._head);
}
list(const list<T> &it)//拷贝构造
{
empty_init();//先把自己初始化
list<T>tmp(it.begin(), it.end());
swap(tmp);
}
~list()
{
clear();
delete _head;//删除头结点
_head = nullptr;
}
void push_back(const T& x)
{
//Node*tail = _head->_prev;//因为循环链表的原因他的尾
//Node* newnode = new Node(x);//这里调用了默认构造函数
//链接过程 __ _head tail newnode
//tail->_next = newnode;//
//newnode->_prev = tail;
//newnode->_next = _head;//这个东西看图很清晰的
//_head->_prev = newnode;
//写好insert可以直接复用
insert(end(), x);//找到尾部,无非就是end这个位置
}
void clear()
{
iterator it = begin();
while (it != end())
{
it = erase(it);//返回下一位置迭代器
}
}
void push_front(const T& x)//头插也可以复用insert
{
insert(begin(), x);
}
iterator erase(iterator pos)
{
assert(pos != end());//判断是不是头结点,头结点不能删除
Node*cur = pos._node;//cur存储迭代器指针
Node*prev = cur->_prev;
Node*next = cur->_next;//找到要删除节点的下一个
//接下来就是三个节点的关系处理了 prev cur next
prev->_next = next;
next->_prev = prev;
delete cur;//释放节点
return iterator(next);/*返回新节点的next*/
}
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);//返回迭代器位置的指针
}
/* void clear()
{
iterator it = begin();
while (it != end())
{
it = erase(it);
}
}*/
void pop_back()
{
erase(--end());//头删
}
void pop_front()
{
erase(begin());
}
private:
Node* _head;//头结点
};
}
这里举例几个重要的接口
//插入的接口
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);//返回迭代器位置的指针
}
//ps:自己画的草图比较丑请见谅结合注释的 push_back来看这个图比较好
当然这个也要注意深浅拷贝问题
这里深浅拷贝参考了stl源码的设计
template <class InputIterator>
list(InputIterator first, InputIterator last)
{
empty_init();//先初始化
while (first != last)//相当与begin !=end
{
push_back(*first);//取数据逐渐尾插
++first;//其实就是便利数据然后尾插
}
}
void empty_init()
{
_head = new Node;//开辟新节点不需要存储数据
_head->_next = _head;
_head->_prev = _head;//形成循环链表
//创建并初始化头结点
}
}
list(const list<T> &it)//拷贝构造
{
empty_init();//先把自己初始化
list<T>tmp(it.begin(), it.end());
swap(tmp);
}
//第二个函数是为了初始化头结点
//第一个函数是为了让迭代器初始化空间
//第三个拷贝构造用的是现代写法