南阳做网站哪家好,网站制作多少页,网站开发维护公司,合肥昱天建设有限公司网站目录
1.list的模拟实现
1.1 成员变量和节点
1.2 迭代器实现
1.2.1 非const的迭代器
1.2.2 const的迭代器
1.2.3 一个模板实现 const 与 非const 迭代器
1.3 增删改查的实现
1.4 拷贝构造函数#xff0c;析构函数与赋值运算符重载
1.5 泛型编程实现打印
2. list 反…目录
1.list的模拟实现
1.1 成员变量和节点
1.2 迭代器实现
1.2.1 非const的迭代器
1.2.2 const的迭代器
1.2.3 一个模板实现 const 与 非const 迭代器
1.3 增删改查的实现
1.4 拷贝构造函数析构函数与赋值运算符重载
1.5 泛型编程实现打印
2. list 反向迭代器的实现
3.list 和 vector 的对比 1.list的模拟实现
要模拟实现list必须要熟悉list的底层结构以及其接口的含义通过上一篇的学习这些内容已基本掌握现在我们来模拟实现list。
1.1 成员变量和节点
首先这里 list 设置成两个成员变量_head 和 _size _head用来指向头节点_size用来记录list有多少个元素。然后还需要自定义list节点的类型。 templateclass Tstruct list_node//节点类{T _data;list_nodeT* _next;list_nodeT* _prev;list_node(const T x T())//构造函数:_data(x), _next(nullptr), _prev(nullptr){}};templateclass Tclass list//list类{typedef list_nodeT Node;void empty_init(){_head new Node;_head-_next _head;_head-_prev _head;_size 0;}list()//构造函数{empty_init();}private:Node* _head;size_t _size;};
1.2 迭代器实现
在vector中我们可以迭代器直接利用原生指针来实现而在list中因为所使用的空间并不是连续的我们需要对迭代器进行封装内部存放一个Node* 类型的指针运算符重载一些要使用的操作。 迭代器要使用的操作 / --* - ! / 1.2.1 非const的迭代器 templateclass Tstruct __list_iterator{typedef list_nodeT Node;typedef __list_iteratorT self;Node* _node;__list_iterator(Node* node nullptr):_node(node){}T operator*(){return _node-_data;}T* operator-()//为数据存放的是自定义类型准备的。{return _node-_data;}};
1.2.2 const的迭代器 const 迭代器要保证指向的内容不能被修改而不是简单的在非const 迭代器前加上一个const这样只是保证了迭代器不能被改变不能进行操作所以必须再实现一个const类型迭代器。
templateclass Tstruct __list_const_iterator{typedef list_nodeT Node;typedef __list_const_iteratorT self;Node* _node;__list_const_iterator(Node* node nullptr):_node(node){}//*it 10;const T operator*(){return _node-_data;}//it-a1 10;const T* operator-()//为数据存放的是自定义类型准备的。{return _node-_data;}};
1.2.3 一个模板实现 const 与 非const 迭代器 可以发现上面两个迭代器只有 * - 返回值不一样写起来比较繁琐我们可以用一个模板实现。
//const_iterator 和 iterator需要实现两个类太繁琐// 可以利用模板实现//同一个类模板模板参数不容类型不同//实例化的参数不容类型完全不同templateclass T, class Ref, class Ptrstruct __list_iterator{typedef list_nodeT Node;typedef __list_iteratorT, Ref, Ptr self;Node* _node;__list_iterator(Node* node nullptr):_node(node){}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-_prev;return tmp;}Ref operator*(){return _node-_data;}Ptr operator-()//为数据存放的是自定义类型准备的。{return _node-_data;}bool operator!(const self it){return _node ! it._node;}bool operator(const self it){return _node it._node;}};
list类中使用迭代器
public:/*typedef __list_iteratorT iterator;typedef __list_const_iteratorT const_iterator;*/typedef __list_iteratorT, T, T* iterator;typedef __list_iteratorT, const T, const T* const_iterator;iterator begin(){return _head-_next;//node指针单参数构造函数隐式类型转换}iterator end(){return _head;}//const迭代器 //const iterator 是修饰的是迭代器本身迭代器就不能了//const迭代器的目的是让内容不能被修改//const_iterator 与iterator是两种完全不同的类型没有什么关系//const_iterator 是重新定义的类型。本身可以修改指向的内容不能修改const_iterator begin()const {return _head-_next;//node指针单参数构造函数隐式类型转换}const_iterator end()const{return _head;}
1.3 增删改查的实现
第一步我们来模拟实现insert 和 erase实现这个接口后我们其他插入删除操作可以通过嵌套这两个函数实现这里使用到了链表的知识不理解的可以画一下图。 iterator insert(iterator pos,const T val){Node* cur pos._node;Node* prev cur-_prev;Node* newnode new Node(val);//prev - newnode - curnewnode-_next cur;newnode-_prev prev;prev-_next newnode;cur-_prev newnode;_size;return iterator(newnode);//构造一个iterator的匿名对象返回//也可以直接返回newnode进行隐式类型转换}iterator erase(iterator pos)//迭代器会失效{if(_head-_next!_head){Node* cur pos._node;Node* prev cur-_prev;Node* next cur-_next;//prev - nextprev-_next next;next-_prev prev;delete cur;_size--;return iterator(next);}}void push_back(const T x){ insert(end(), x);}void push_front(const T x){insert(begin(), x);}void pop_back(){erase(--end());}void pop_front(){erase(begin());}void clear(){iterator it begin();while (it ! end()){it erase(it);}}
1.4 拷贝构造函数析构函数与赋值运算符重载
这里实现构造函数析构函数与赋值运算符重载。通过嵌套可以实现的更简洁。 list(const listT l){empty_init();for (auto e : l){push_back(e);}}void swap(listT l){std::swap(_head, l._head);std::swap(_size, l._size);}listT operator(listT l){//这里传参已经是实现拷贝构造,只需交换*this和l 就可以实现赋值赋值运算符重载swap(l);return *this;}~list(){clear();delete _head;}
1.5 泛型编程实现打印
我们可以使用一个模板函数来实现可以打印不同容器的内容。
void test4(){listint l1;l1.push_back(1);l1.push_back(2);l1.push_back(3);l1.push_back(4);l1.push_back(5);l1.push_back(6);//print_list(l1);print_Container(l1);liststring l2;l2.push_back(12345678);//这里list.push_back 不会涉及深拷贝的问题 //vector是因为开空间要拷贝原来数据l2.push_back(12345678);l2.push_back(12345678);l2.push_back(12345678); //print_list(l2);print_Container(l2);vectorstring v;v.push_back(1111111111111);v.push_back(1111111111111);v.push_back(1111111111111);v.push_back(1111111111111);v.push_back(1111111111111);print_Container(v);}
1.实现只能打印vector int 的函数 void print_list(const listint l){listint::const_iterator it l.begin();//返回const迭代器while (it ! l.end()){//*it 1;//const迭代器不能修改cout *it ;it;}cout endl;}
2.实现可以打印 vectorT 的函数。
之前讲class 和 typename 的不同之处在这里可以体现。 templatetypename T void print_list(const listT l){//这里要加 typename //listT 未实例化编译器不能去他里面找//不能判断const_iterator 是一个静态成员变量还是一个内嵌类型//所以加一个typename 就是告诉编译器这里是一个类型等它实例化了再去取通过初步检查typename listT::const_iterator it l.begin();while (it ! l.end()){cout *it ;it;}cout endl;}
3.实现可以打印所有容器的函数 templatetypename Containervoid print_Container(const Container con){typename Container::const_iterator it con.begin(); while (it ! con.end()){cout *it ;it;}cout endl;}//模板泛型编程本质本来应该由我们做的事情交给编译器去做
2. list 反向迭代器的实现
通过前面例子知道反向迭代器的就是正向迭代器的--反向迭代器的--就是正向迭代器的因此反向迭代器的实现可以借助正向迭代器即反向迭代器内部可以包含一个正向迭代器对正向迭代器的接口进行包装即可。
templateclass Iterator
class ReverseListIterator
{// 注意此处typename的作用是明确告诉编译器Ref是Iterator类中的类型而不是静态成员变量 // 否则编译器编译时就不知道Ref是Iterator中的类型还是静态成员变量// 因为静态成员变量也是按照 类名::静态成员变量名 的方式访问的public:typedef typename Iterator::Ref Ref;typedef typename Iterator::Ptr Ptr;typedef ReverseListIteratorIterator Self;public:// 构造ReverseListIterator(Iterator it) : _it(it){}// 具有指针类似行为Ref operator*(){Iterator temp(_it);--temp;return *temp;}Ptr operator-(){ return (operator*());}//// 迭代器支持移动Self operator(){--_it;return *this;}Self operator(int){Self temp(*this);--_it;return temp;}Self operator--(){_it;return *this;}Self operator--(int){Self temp(*this);_it;return temp;}// 迭代器支持比较bool operator!(const Self l)const{ return _it ! l._it;}bool operator(const Self l)const{ return _it ! l._it;}Iterator _it;
};
3.list 和 vector 的对比
vector与list都是STL中非常重要的序列式容器由于两个容器的底层结构不同导致其特性以及应用场景不同其主要不同如下
vectorlist底 层 结 构动态顺序表一段连续空间带头结点的双向循环链表随 机 访 问支持随机访问访问某个元素效率O(1)不支持随机访问访问某个元素 效率O(N)插 入 和 删 除任意位置插入和删除效率低需要搬移元素时间复杂 度为O(N)插入时有可能需要增容增容开辟新空 间拷贝元素释放旧空间导致效率更低任意位置插入和删除效率高不 需要搬移元素时间复杂度为 O(1)空 间 利 用 率底层为连续空间不容易造成内存碎片空间利用率 高缓存利用率高底层节点动态开辟小节点容易 造成内存碎片空间利用率低 缓存利用率低迭 代 器原生态指针对原生态指针(节点指针)进行封装迭 代 器 失 效在插入元素时要给所有的迭代器重新赋值因为插入 元素有可能会导致重新扩容致使原来迭代器失效删 除时当前迭代器需要重新赋值否则会失效插入元素不会导致迭代器失效 删除元素时只会导致当前迭代 器失效其他迭代器不受影响使 用 场 景需要高效存储支持随机访问不关心插入删除效率大量插入和删除操作不关心随 机访问
本篇结束