当前位置: 首页 > news >正文

C++list的模拟实现

链表节点

	template<class T>struct ListNode{ListNode(const T& data = T()):	_data(data){}ListNode<T> * _prev=nullptr;ListNode<T> *_next=nullptr;T _data;};

因为之后要访问这个类的成员变量函数和结构体,所以在这里将class直接改为struct 构造函数

 成员变量:

typedef  ListNode<T> Node;

typedef ListIterator<T> iterator;
typedef ListconstIterator<T> const_iterator;

Node* _head;

该链表的实现是带头双向循环链表

迭代器的实现:

因为list不像vector和string那样开连续的空间,不能直接++访问下一个节点,所以这里设置迭代器时要另外封装一个类来实现

iterator:

	template<class T>class ListIterator {public:typedef ListNode<T> Node;Node* _node;ListIterator(Node* node):_node(node)//用node初始化{}ListIterator<T> operator++(){_node = _node->_next;return *this;}ListIterator<T> operator++(int){ListIterator<T> tem(*this);_node = _node->_next;return tem;}ListIterator<T> operator--(){_node = _node->_prev;return *this;}bool operator!=(ListIterator<T> it){return _node != it._node;}bool operator==(ListIterator<T> it){return _node == it._node;}ListIterator<T> operator--(int){ListIterator<T> tem(*this);_node = _node->_prev;return tem;}T& operator *(){return _node->_data;}T* operator->(){return &(_node->_data);}};

 const_iterator:

	template<class T>class ListconstIterator{public:typedef ListNode<T> Node;Node* _node;ListconstIterator(Node* node):_node(node){}ListconstIterator<T> operator++(){_node = _node->_next;return *this;}ListconstIterator<T> operator++(int){ListconstIterator<T> tem(*this);_node = _node->_next;return tem;}ListconstIterator<T> operator--(){_node = _node->_prev;return *this;}bool operator!=(ListconstIterator<T> it){return _node != it._node;}bool operator==(ListconstIterator<T> it){return _node == it._node;}ListconstIterator<T> operator--(int){ListconstIterator<T> tem(*this);_node = _node->_prev;return tem;}const T& operator *(){return _node->_data;}const T* operator->()//指向内容不能修改{return &(_node->_data);}};

 对const_iterator的实现,因为指向内容不能修改,所以又封装了一个类来实现,其实还有另一种方法更为便捷,那就是增加两个模版参数

	template<class T,class Ptr,class Ref>class ListIterator {public:typedef ListNode<T> Node;Node* _node;ListIterator(Node* node):_node(node)//用node初始化{}ListIterator<T,Ptr,Ref> operator++(){_node = _node->_next;return *this;}ListIterator<T, Ptr, Ref> operator++(int){ListIterator<T, Ptr, Ref> tem(*this);//拷贝构造,浅拷贝_node = _node->_next;return tem;}ListIterator<T, Ptr, Ref> operator--(){_node = _node->_prev;return *this;}bool operator!=(ListIterator<T, Ptr, Ref> it){return _node != it._node;}bool operator==(ListIterator<T, Ptr, Ref> it){return _node == it._node;}ListIterator<T, Ptr, Ref> operator--(int){ListIterator<T, Ptr, Ref> tem(*this);//拷贝构造,浅拷贝,不需要写赋值和拷贝构造,都是浅拷贝_node = _node->_prev;return tem;}Ptr operator *(){return _node->_data;}Ref operator->(){return &(_node->_data);}};

        typedef ListIterator<T,T& , T*> iterator;
        typedef ListIterator<T,const T&,const T*> const_iterator;

增加两个模板参数后,编译器进行实例化时会帮你生成两个类

 需要注意的几点:

1.这个类不用自己写拷贝构造和赋值运算符重载,因为编译器会默认生成,仅仅浅拷贝就7可以了

2.对->运算符的解释:

	class Pos{public:Pos(int x=0,int y=0):_x(x),_y(y){}//private:int _x;int _y;};void test3(){list<Pos> lt;lt.push_back(Pos(1,1));lt.push_back(Pos(2, 2));lt.push_back(Pos(3, 3));lt.push_back(Pos(4, 4));list<Pos>::iterator it = lt.begin();while (it != lt.end()){//cout << *it << " ";错误//cout << it.operator->()->_x<<" "<<it.operator->()->_y << " ";cout << it->_x<<it->_y;//与上面等价it++;}cout << endl;}

当自定义类型没有重载流插入不能够直接打印数据,但调用->可以很好地解决问题,其实it->_x与it.operator->()->_x等价,只写一个->是为了可读性

构造: 

		void Init_list(){_head = new Node;_head->_next = _head;_head->_prev = _head;}list(){Init_list();}
		 list(initializer_list<T> il){Init_list();//先创造一个头结点for (const auto& e : il){push_back(e);}}

 拷贝构造:

		 list(const list<T>& lt){Init_list();for (const auto& e : lt){push_back(e);}}

赋值运算符重载:

		list<T>& operator=( list<T> lt){std::swap(lt._head, _head);return *this;}

 析构函数:

	~list(){clear();delete _head;_head = nullptr;}void clear(){iterator it = begin();while (it != end()){it=erase(it);}}

 push_back:

	void push_back(const T& val){Node* newnode = new Node(val);newnode->_next = _head;newnode->_prev = _head->_prev;_head->_prev->_next = newnode;_head->_prev = newnode;}

pop_back:

		void pop_back(){Node* tem = _head->_prev;_head->_prev->_prev->_next = _head;_head->_prev = _head->_prev->_prev;delete tem;tem = nullptr;}

insert:

	iterator insert(iterator pos, const T& val){Node* newnode = new Node(val);Node* pcur = pos._node;newnode->_next = pcur;newnode->_prev = pcur->_prev;pcur->_prev->_next = newnode;pcur->_prev = newnode;return iterator(newnode);}

这里的插入不会出现迭代器失效问题 

erase:

		iterator erase(iterator pos){assert(pos != end());Node* pcur = pos._node;Node* next = pcur->_next;pcur->_prev->_next = pcur->_next;pcur->_next->_prev = pcur->_prev;delete pcur;pcur = nullptr;return iterator(next);}

erase会出现迭代器失效问题,该函数返回删除位置的下一个位置的迭代器,所以进行删除后要及时更新迭代器 

 push_front:

		void push_front(const T& val){insert(begin(), val);}

pop_front:

		void pop_front(){assert(begin() != end());erase(begin());}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 【Python123题库】#统计单词的数量 #各位数字之和为5的数 #输出单词
  • qt 按钮链接一个槽函数
  • 昇思25天学习打卡营第十六天|基于MindSpore的GPT2文本摘要
  • 操作系统---进程的同步和互斥(易错知识点梳理)
  • 银行小额支付系统的全面解析
  • jQuery Mobile 实例:构建响应式移动网页的实践指南
  • 【Javascript】微信小程序项目结构目录详解
  • 鸿蒙 arkts 实现手机号中间四位隐藏, 可以使用 substring [ 简单适用新手 ]
  • RedHat运维-Linux存储管理基础4-LVM的相关减小操作
  • 服务攻防——中间件Jboss
  • 1.认识微服务
  • HackTheBox--BoardLight
  • 1.DDR3 SO-DIMM 内存条硬件总结
  • 【C语言】<常量> 之群英荟萃
  • 2024年全面导入APS系统:提升工厂生产效率的策略
  • 《Javascript数据结构和算法》笔记-「字典和散列表」
  • 《剑指offer》分解让复杂问题更简单
  • 2018一半小结一波
  • If…else
  • iOS帅气加载动画、通知视图、红包助手、引导页、导航栏、朋友圈、小游戏等效果源码...
  • js面向对象
  • learning koa2.x
  • leetcode46 Permutation 排列组合
  • PAT A1092
  • Quartz初级教程
  • SpingCloudBus整合RabbitMQ
  • yii2权限控制rbac之rule详细讲解
  • 搭建gitbook 和 访问权限认证
  • 记一次用 NodeJs 实现模拟登录的思路
  • 简单数学运算程序(不定期更新)
  • 开源中国专访:Chameleon原理首发,其它跨多端统一框架都是假的?
  • 如何使用 JavaScript 解析 URL
  • 世界编程语言排行榜2008年06月(ActionScript 挺进20强)
  • 首页查询功能的一次实现过程
  • 一个项目push到多个远程Git仓库
  • 正则学习笔记
  • ​比特币大跌的 2 个原因
  • ​软考-高级-系统架构设计师教程(清华第2版)【第15章 面向服务架构设计理论与实践(P527~554)-思维导图】​
  • #传输# #传输数据判断#
  • (2024)docker-compose实战 (8)部署LAMP项目(最终版)
  • (Oracle)SQL优化技巧(一):分页查询
  • (超简单)构建高可用网络应用:使用Nginx进行负载均衡与健康检查
  • (二)【Jmeter】专栏实战项目靶场drupal部署
  • (分享)自己整理的一些简单awk实用语句
  • (附源码)spring boot基于Java的电影院售票与管理系统毕业设计 011449
  • (附源码)springboot宠物医疗服务网站 毕业设计688413
  • (每日持续更新)jdk api之FileReader基础、应用、实战
  • (牛客腾讯思维编程题)编码编码分组打印下标(java 版本+ C版本)
  • (四)activit5.23.0修复跟踪高亮显示BUG
  • (文章复现)基于主从博弈的售电商多元零售套餐设计与多级市场购电策略
  • (中等) HDU 4370 0 or 1,建模+Dijkstra。
  • (转)nsfocus-绿盟科技笔试题目
  • (转)平衡树
  • **CI中自动类加载的用法总结
  • .dwp和.webpart的区别