目录
前言
list,其实就是我们C语言数据结构学过的带头双向循环链表,每一个节点都有指向前一个和后一个节点的指针,除头节点外都存储数据。
list的接口与string和vector的接口很类似,因此博客不再过多演示。
由于物理结构的差异(内存存储位置不连续),与string和vector不同,list的模拟实现中不能再使用原生指针作为迭代器进行封装,因此本博客的重心会放在list迭代器的实现。
一、接口
大体上的接口我们在前面的vector和list就已经很熟悉了,由于list的本身特性,库里面增添了remove和sort的接口, remove是删除所有等于value的元素,remove_if是删除所有符合条件的元素,这个判断是否符合条件是需要传仿函数或者函数指针过去的。
仿函数实际是一个类实例化出的对象,通过运算符重载达到的类似函数调用的效果,这个以后会具体写代码来讲解实现,这里给出文档的示例,了解一下即可
另外值得一提的是,由于物理空间上的限制,list的sort效率并不高,我们对list进行排序的时候,也可以考虑先用迭代器构造将其数据转到相应的vector里,再用迭代器构造出一个list存储排序后的数据。
二、迭代器
由于容器物理空间分布的不同,容器的迭代器可以大致分为三种类型:单向,双向和随机迭代器。
它们之间是继承的关系,继承简单来说就是子类在继承父类原有内容基础上增添了新的功能。
单向迭代器 :只能++,不能--
双向迭代器:只能++和--,不能+和-
随机迭代器:支持+和-,以及+=,++,-=,--等各种操作
由于list物理结构的原因,它的迭代器只支持++和--,也就是双向迭代器,可以利用对list进行遍历等等操作。
实际上,如果非要支持+和-,也不是不行,但是时间复杂度会是O(N),所以就放弃了这种方式,如果我们需要跳跃多个节点,可以利用while循环让迭代器++或者--。
三、模拟实现
1.基本框架
list,带头双向链表,实现它自然需要结点(存储当前结点数据以及前后结点位置)和迭代器(具体实现后面会细说),把两者封装起来成list,list的私有成员即为头节点指针和_size,我们每次插入和删除数据都对size进行++或--操作,方便记录结点个数。
namespace muss
{
template<class T>
struct list_node
{
T _data;
list_node<T>* _next;
list_node<T>* _prev;
};
template<class T>
struct list_iterator
{
};
template<class T>
class list
{
public:
private:
Node* _head;
size_t _size;
};
}
这是最基本的框架,我们后面会对其进行完善
2.迭代器处理
对于迭代器的实现,我们为了让其能实现++,--的遍历操作,我们让封装起来的迭代器储存对应结点的地址,这样方便我们通过它的两个指针来找到前后两个结点。通过运算符重载,实现它的遍历操作,也就是可以实现++和--。
一个容器的迭代器一般都需要实现两个版本,const和非const,然而我们对其分别进行实现,会发现一个问题,除了一些成员函数的返回值外,其它的部分,这两个迭代器的实现几乎一模一样,这样就出现了很多代码相同但没有很好复用的情况,处理这种情况,库里面是这样做的:
库里面模板传了两个额外的参数作为了返回值,传什么样的模板参数就决定了会实例化除出一个怎样的迭代器版本。其实两种方式生成的迭代器效果是一样的,这是通过模板实现代码复用的一种手段。
3.迭代器失效问题
list的迭代器失效主要是因为结点的删除导致其对应位置迭代器的失效,由于结点的增加并不会改变其它结点的地址等,所以结点的增加并不会带来迭代器失效的问题。
可以看到,为了支持连续删除,erase会把删除元素的下一个结点的迭代器返回,我们可以利用这个返回值进行连续删除。
namespace muss
{
template<class T>
class list
{
public:
iterator erase(iterator pos)
{
assert(pos != end());
node* prev = pos._node->_prev;
node* next = pos._node->_next;
prev->_next = next;
next->_prev = prev;
delete pos._node;
--_size;
return next;
}
private:
Node* _head;
size_t _size;
};
}
4.模拟实现整体代码
list.h
#pragma once
#include <assert.h>
namespace muss
{
template<typename T>
struct list_node
{
typedef list_node<T> node;
T _data;
node* _prev;
node* _next;
list_node(const T& data = T())
: _data(data)
, _prev(nullptr)
, _next(nullptr)
{}
};
// 模板参数: T、 T&、 T*
template<typename T, typename Ref, typename Ptr>
struct list_iterator
{
typedef list_node<T> node; // list节点
typedef list_iterator<T, Ref, Ptr> Self; // 迭代器自身类型
node* _node; // 迭代器遍历的关键:存储节点地址
list_iterator(node* node)
:_node(node)
{}
Ref operator*()
{
return _node->_data;
}
// 详细情况在test5,迭代器的->做了特殊处理
Ptr operator->()
{
return &_node->_data;
}
// 前置++、--
Self& operator++()
{
_node = _node->_next;
return *this;
}
Self& operator--()
{
_node = _node->_prev;
return *this;
}
// 后置++、--
Self& operator++(int)
{
Self tmp(*this);
_node = _node->_next;
return tmp;
}
Self& operator--(int)
{
Self tmp(*this);
_node = _node->_next;
return tmp;
}
bool operator==(const Self& it) const
{
return _node == it._node;
}
bool operator!=(const Self& it) const
{
return _node != it._node;
}
};
template<typename 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
void empty_initialize()
{
_head = new node;
_head->_prev = _head->_next = _head;
_size = 0;
}
list()
{
empty_initialize();
}
// 支持初始化列表初始化
list(initializer_list<T> il)
{
empty_initialize();
for (auto& e : il)
{
push_back(e);
}
}
list(const list<T>& lt)
{
empty_initialize();
for (auto& e : lt)
{
push_back(e);
}
}
~list()
{
clear();
delete _head;
_head = nullptr;
}
// 不能返回引用,因为是中间变量的引用,使不得
iterator begin()
{
// 返回头节点的下一个节点
// 最拉跨
//node* node = _head->_next;
//iterator ret(node);
//return ret;
// 匿名对象
//return iterator(_head->_next);
// 强制类型转化
return _head->_next;
}
iterator end()
{
return _head;
}
const_iterator begin() const
{
return _head->_next;
}
const_iterator end() const
{
return _head;
}
bool empty() const
{
return _head->_next == _head;
}
size_t size() const
{
return _size;
}
iterator insert(iterator it, const T& value = T())
{
node* newnode = new node(value);
node* prev = it._node->_prev;
node* next = it._node;
prev->_next = newnode;
newnode->_prev = prev;
next->_prev = newnode;
newnode->_next = next;
++_size;
return newnode;
}
void push_back(const T& value = T())
{
insert(end(), value);
}
void push_front(const T& value = T())
{
insert(begin(), value);
}
iterator erase(iterator pos)
{
assert(pos != end());
node* prev = pos._node->_prev;
node* next = pos._node->_next;
prev->_next = next;
next->_prev = prev;
delete pos._node;
--_size;
return next;
}
void pop_back()
{
erase(--end());
}
void pop_front()
{
erase(begin());
}
void clear()
{
auto it = begin();
while (it != end())
{
it = erase(it);
}
}
void swap(list<T>& lt)
{
std::swap(_size, lt._size);
std::swap(_head, lt._head);
}
// l1 = l2
// 为什么能得到深拷贝:
// 传参的时候传值传参,调用自己写的拷贝构造深拷贝
// 这里lt和l2无关,交换后,释放lt也就是原来的l1,l1得到lt也就是l2的深拷贝
list<T>& operator=(list<T> lt)
{
swap(lt);
return *this;
}
private:
node* _head;
size_t _size;
};
template<class Container>
void print_container(const Container& con)
{
typename Container::const_iterator it = con.begin();
while (it != con.end())
{
cout << *it << " ";
++it;
}
cout << endl;
}
void list_test1()
{
list<int> lt;
lt.push_back(1);
lt.push_back(2);
lt.push_back(3);
lt.push_back(5);
lt.push_back(6);
lt.push_back(7);
lt.push_back(8);
lt.push_back(9);
lt.push_back(10);
print_container(lt);
lt.erase(lt.begin());
lt.erase(--lt.end());
list<int>::iterator ilt = lt.begin();
print_container(lt);
ilt++;
ilt++;
ilt++;
ilt++;
lt.erase(ilt);
print_container(lt);
lt.clear();
print_container(lt);
lt.push_back(1);
lt.push_back(2);
lt.push_back(3);
print_container(lt);
lt.empty_initialize();
print_container(lt);
lt.push_back(1);
lt.push_back(2);
lt.push_back(3);
print_container(lt);
}
void list_test2()
{
list<int> l1;
list<int> l2;
l1.push_back(1);
l1.push_back(2);
l1.push_back(3);
l2.push_back(8);
l2.push_back(8);
l2.push_back(8);
l2.push_back(8);
l2.push_back(8);
print_container(l1);
print_container(l2);
swap(l1, l2);
print_container(l1);
print_container(l2);
l2 = l1;
print_container(l1);
print_container(l2);
l1.push_back(123);
print_container(l1);
print_container(l2);
//
}
void list_test3()
{
list<string> ls;
ls.push_back("abcdefg1");
ls.push_back("abcdefg2");
ls.push_back("abcdefg3");
ls.push_back("abcdefg4");
ls.push_back("abcdefg5");
ls.push_back("abcdefg6");
print_container(ls);
ls.push_front("haha");
print_container(ls);
ls.insert(++ls.begin(), "wohaoshuai");
print_container(ls);
ls.pop_back();
print_container(ls);
ls.pop_front();
print_container(ls);
ls.erase(++(++ls.begin()));
print_container(ls);
}
// =
void list_test4()
{
list<int> l1 = { 1,2,3,4,5 };
list<int> l2 = { 5,6,7 };
print_container(l1);
print_container(l2);
l1 = l2;
print_container(l1);
print_container(l2);
l2.push_back(15);
print_container(l1);
print_container(l2);
}
struct AA
{
int a1 = 1;
int a2 = 2;
};
// ->
void list_test5()
{
list<int> l1 = { 1,2,3,4,5 };
auto it = l1.begin();
//cout << it->
// 不能这样,下面那个存struct的地址,struct里面有元素,所以才能访问
// 而这里存int的地址,内没有元素,不能访问
list<AA> lsa;
lsa.push_back(AA());
lsa.push_back(AA());
lsa.push_back(AA());
lsa.push_back(AA());
auto ita = lsa.begin();
//Ptr operator->()
//{
// return &node->_data;
//}
// 其实是两个箭头,为了可读性而特殊处理了
cout << ita->a1 << " " << ita->a2 << endl;
cout << ita.operator->()->a1 << " " << ita.operator->()->a2 << endl;
}
void list_test6()
{
list<int> l1 = { 1,2,3,4,5 };
auto it = l1.begin();
++it;
auto ret = l1.insert(it, 7);
cout << *ret << endl;
}
}
test.cpp
#include<iostream>
#include<list>
using namespace std;
#include"List.h"
int main()
{
muss::list_test2();
return 0;
}
此博客完结~~~~~