一、接口介绍
1.构造
//无参构造
list<int> lt1;
//n个val构造
list<int> lt2(3, 10);
//任意类型的迭代器区间构造
int arr[] = { 3,5,1,7,9,10 };
list<int> lt3(arr, arr + sizeof(arr) / sizeof(arr[0]));
//拷贝构造
list<int> lt4(lt3);
//赋值构造
list<int> lt5;
lt5 = lt4;
2.修改
int a1[] = { 4,3,5,2,7,9,10 };
list<int> lt1(a1,a1+sizeof(a1)/sizeof(a1[0]));
int a2[] = { 14,13,15,12,17,19,11 };
//用任意类型的迭代器区间替换lt1的内容,并调整链表大小
lt1.assign(a2, a2 + sizeof(a2) / sizeof(a2[0]));
//用n个val替换lt1的内容,并调整链表大小
lt1.assign(3,8);
int a1[] = { 4,3,5,2,7};
list<int> lt;
//头插,头删
lt.push_front(4);
lt.pop_front();
//尾插,尾删
lt.push_back(5);
lt.pop_back();
//任意迭代器位置插入val
lt.insert(lt.begin(), 4);
//任意迭代器位置插入n个val
lt.insert(lt.begin(), 3, 4);
//在任意迭代器位置,插入一个任意类型的迭代器区间
list<string> lt1;
string s("hello world");
lt1.insert(lt1.begin(),s.begin(), s.end());
//删除任意迭代器位置的val
lt.erase(lt.begin());
//删除任意迭代器区间的val
lt.erase(++lt.begin(), --lt.end());
//变更链表的size,并初始化多余的空间
lt.resize(3, 8);
//清空
lt.clear();
3.操作
int a1[] = { 4,3,5,2,7};
list<int> lt1(a1,a1+sizeof(a1)/sizeof(a1[0]));
//将lt2的内容转移至lt1的任意迭代器位置
list<int> lt2(5, 7);
lt1.splice(++lt1.begin(), lt2);
//将lt3的任意迭代器位置的val转移至lt1的任意迭代器位置
list<int> lt3(5, 8);
lt1.splice(lt1.begin(), lt3,lt3.begin());
//将lt4的任意迭代器区间的val转移至lt1的任意迭代器位置
list<int> lt4(5, 9);
lt1.splice(lt1.begin(), lt4,lt4.begin(),lt4.end());
//查找val并删除
lt1.remove(3);
//排序,效率极低,一般使用算法库中的sort
struct greate
{
bool operator()(int x,int y)
{
return x > y;
}
};
int a1[] = { 4,3,5,2,7};
list<int> lt1(a1,a1+sizeof(a1)/sizeof(a1[0]));
lt1.sort(greate());
//归并之前两个链表必须有序,不然会抛异常
int a1[] = { 4,3,5,2,7 };
list<int> lt1(a1,a1+sizeof(a1)/sizeof(a1[0]));
lt1.sort();
int a2[] = { 14,1,15,2,17 };
list<int> lt2(a2, a2 + sizeof(a2) / sizeof(a2[0]));
lt2.sort();
//归并后lt2的链表被清空
lt1.merge(lt2);
//逆置
lt1.reverse();
二、模拟实现
1.实现难点
因为在列表的头初始化时要用到无参构造,插入新节点时要用到带参构造,所以要给node节点全缺省构造.
list的初始化,出了赋值构造,其他的构造都需要先初始化头结点.
因为是双向带头循环链表,所以迭代器的头是head的下一个位置,尾是head的位置,插入是在节点之前插入,删除是删除当前节点,end()节点不能删除.
list的迭代器是双向迭代器,有些算法中要求使用随机迭代器,比如sort排序list不能使用.const迭代器不能直接加const,会导致迭代器的pnode的地址不能被修改,而const迭代器的初衷是想让,pnode指向的内容不能修改,所以要控制和->重载的常性.但是又需要可修改和不可修改两种实现,不想代码冗余就必须增加两个模板参数,一个控制pnode的data,一个控制pnode的data的地址.
2.代码实现
#pragma once
#include <iostream>
#include <cassert>
#include<algorithm>
using namespace std;
namespace kk
{
template <class T>
//节点结构
struct listNode
{
listNode<T>* _next;
listNode<T>* _previous;
T _data;
//在插入新节点的时候要用到带参构造,链表初始化要用到无参构造
listNode(const T& data=T())
:_data(data),_next(nullptr),_previous(nullptr)
{}
};
template <class T, class ref, class ptr>
struct listIterator
{
typedef listNode<T> node;
typedef listIterator<T, ref, ptr> self;
node* _pnode;
listIterator(node* pnode)
:_pnode(pnode)
{}
ref operator*()
{
return _pnode->_data;
}
ptr 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->_previous;
return *this;
}
self operator--(int)
{
self tmp(*this);
_pnode = _pnode->_previous;
return tmp;
}
bool operator!=(const self& s)
{
//比较的是节点的地址
return _pnode != s._pnode;
}
bool operator==(const self& s)
{
return _pnode == s._pnode;
}
};
template <class T>
class list
{
typedef listNode<T> node;
public:
typedef listIterator<T, T&, T*> iterator;
typedef listIterator<T, const T&, const T*> const_iterator;
iterator begin()
{
/*○(尾)<-->1(头)<-->2<-->3 */
return iterator(_phead->_next);
}
iterator end()
{
return iterator(_phead);
}
const_iterator begin() const
{
return const_iterator(_phead->_next);
}
const_iterator end() const
{
return const_iterator(_phead);
}
//初始化链表
void emptyListInit()
{
_phead = new node;
_phead->_next = _phead;
_phead->_previous = _phead;
}
list()
{
emptyListInit();
}
//释放链表节点内存
void clear()
{
iterator it = begin();
while (it != end())
{
erase(it++);
}
}
~list()
{
clear();
delete _phead;
_phead = nullptr;
}
list(const list<T>& lt)
{
emptyListInit();
for (auto e : lt)
{
push_back(e);
}
}
void swap(list<T>& lt)
{
std::swap(_phead, lt._phead);
}
list& operator=(list<T> lt)
{
//赋值构造是默认构造之后的操作,所以不用初始化空链表
swap(lt);
return *this;
}
template <class inputIterator>
list(inputIterator first, inputIterator last)
{
emptyListInit();
while (first != last)
{
push_back(*(first++));
}
}
void push_back(const T& data)
{
/*(插入)<-->○(end)<-->1(begin)<-->2<-->3 */
insert(end(), data);
}
void pop_back()
{
/*○(end)<-->1(begin)<-->2<-->3(删除) */
erase(--end());
}
void push_front(const T& data)
{
/*○(end)<-->(插入)<-->1(begin)<-->2<-->3 */
insert(begin(), data);
}
void pop_front()
{
/*○(end)<-->1(删除)<-->2<-->3 */
erase(begin());
}
void insert(iterator pos, const T& data)
{
//pos位置的节点
node* cur = pos._pnode;
//pos位置的前一个节点
node* pre = pos._pnode->_previous;
node* newNode = new node(data);
//链接在cur和pre之间
newNode->_next = cur;
cur->_previous = newNode;
newNode->_previous = pre;
pre->_next = newNode;
}
iterator erase(iterator pos)
{
assert(pos != end());
//pos之前的节点
node* pre = pos._pnode->_previous;
//pos之后的节点
node* next = pos._pnode->_next;
//链接pre和next
pre->_next = next;
next->_previous = pre;
//释放pos位置的节点
delete pos._pnode;
pos._pnode = nullptr;
//返回pos的下一个位置的节点
return iterator(next);
}
private:
node* _phead;
};
//构造+迭代器 测试
void test_list1()
{
kk::list<int> lt;
lt.push_back(1);
lt.push_back(2);
lt.push_back(3);
lt.push_back(4);
kk::list<int>::iterator it = lt.begin();
while (it != lt.end())
{
cout << *(it++);
}
cout << endl;
list<int> lt1;
lt1 = lt;
for (auto e : lt1)
{
cout << e;
}
cout << endl;
}
//任意位置删除测试
void test_list2()
{
int arr[] = { 3,5,6,7,8,4,5,6,7 };
list<int> lt(arr, arr + sizeof(arr) / sizeof(arr[0]));
for (auto e : lt)
{
cout << e;
}
cout << endl;
lt.erase(lt.begin());
for (auto e : lt)
{
cout << e;
}
cout << endl;
lt.erase(++lt.begin());
for (auto e : lt)
{
cout << e;
}
cout << endl;
lt.erase(--lt.end());
for (auto e : lt)
{
cout << e;
}
cout << endl;
}
//清空测试
void test_list3()
{
int arr[] = { 3,5,6,7,8,4,5,6,7 };
list<int> lt(arr, arr + sizeof(arr) / sizeof(arr[0]));
for (auto e : lt)
{
cout << e;
}
cout << endl;
lt.clear();
for (auto e : lt)
{
cout << e;
}
cout << endl;
lt.push_back(1);
lt.push_back(2);
lt.push_back(3);
lt.push_back(4);
for (auto e : lt)
{
cout << e;
}
cout << endl;
}
//->重载测试
struct AA
{
int _a=0;
int _b = 0;
AA(int a=0,int b=0)
:_a(a)
,_b(b)
{}
};
void test_list4()
{
list<AA> lt;
lt.push_back(AA(1, 2));
lt.push_back(AA(3, 4));
auto it = lt.begin();
cout << it->_a << " " << it->_b << endl;
}
}