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

C++(list的简单实现,着重点是迭代器)

本文适合能自主实现双向链表增删的有功底的人,如果不会的话可以看我以前使用c实现的双向链表。

C++中list是双向链表,forword_list才是单链表

目录

1.节点(list_node)

2.链表的成员函数的实现

3.iterator迭代器

4.const_iterator 迭代器

5.合并iterator和const_iterator


1.节点(list_node)

	template<class T>
	struct list_node
	{
		list_node(const T& val = T())
			:_val(val)//这里是初始化
		{
			_next = _prev = this;//使指针指向自己
			//_val = val;//为什么不在写?因为这里赋值,因为模板参数可能是T = const int等,const不支持修改
		}
		list_node<T>* _next;
		list_node<T>* _prev;
		T _val;
	};

初始化列表是初始化,而代码块中的代码是赋值。const类型的数据一旦初始化后,就不能在修改其值。

2.链表的成员函数的实现

这里就是链表的增删问题了这里就不讲了,直接给代码。

	template<class T>
	class list
	{
		typedef list_node<T>* PNode;
		typedef list_node<T> Node;
    public:
        //构造
		list()
		{
			_phead = new Node(-1);
		}
        //拷贝构造
		list(const list<T>& l)
		{
			PNode pcur = l._phead->_next;
			while (pcur != l._phead)
			{
				push_back(pcur->_val);
			}
		}


        //深拷贝实现的复制
		list<T>& operator=(const list<T>& l)
		{
			PNode pcur = l._phead->_next;
			while (pcur != l._phead)
			{
				push_back(pcur->_val);
			}
			return *this;
		}
        //现代写法
        list<T>& operator=(list<T> l)
        {
            std::swap(_phead,l._phead);
            return *this;
        }

        //析构
		~list()
		{
			delete(_phead);
		}
        


		iterator begin()
		{
			return _phead->_next;
		}
		iterator end()
		{
			return _phead;
		}


		size_t size()
		{
			PNode pcur = _phead->_next;
			int cout = 0;
			while (pcur != _phead)
			{
				count++;
				pcur = pcur->_next;
			}
			return count;
		}

		bool empty()
		{
			return _phead->_next == _phead;
		}

		T& front()
		{
			return _phead->_next->_val;
		}

		T& back()
		{
			PNode pcur = _phead->_next;
			while (pcur->_next != _phead)
			{
				pcur = pcur->_next;
			}
			return pcur->_val;
		}


        //push,pop可以复用insert和erase
		void push_back(const T& val) { insert(end(), val); }
		void pop_back() { erase(--end()); }
		void push_front(const T& val) { insert(begin(), val); }
		void pop_front() { erase(begin()); }
		// 在pos位置前插入值为val的节点
		iterator insert(iterator pos, const T& val)
		{
			PNode newnode = new Node(val);
			newnode->_prev = pos.operator->()->_prev;
			pos.operator->()->_prev->_next = newnode;
			newnode->_next = pos.operator->();
			pos.operator->()->_prev = newnode;

			return newnode;
		}
		// 删除pos位置的节点,返回该节点的下一个位置
		iterator erase(iterator pos)
		{
			PNode del = pos.operator->();
			PNode ret = del->_next;
			del->_prev->_next = del->_next;
			del->_next -> _prev = del->_prev;
			delete del;
			return ret;
		}
		void clear()
		{
			PNode* pcur = _phead;
			PNode* next;
			while (pcur != _phead)
			{
				next = pcur->_next;
				delete pcur;
				pcur = next;
			}
		}
        //交换的是资源
		void swap(list<T>& l)
		{
			std::swap(_phead, l._phead);
		}
        
	private :
		PNode _phead;//指向哨兵位
	};

3.iterator迭代器

iterator迭代器的本质就是控制指向节点的指针的向前和向后移动。

	template<class T>
	class Iterator
	{
		typedef list_node<T>* PNode;
		typedef list_node<T> Node;
		typedef Iterator<T> Self;
	public:
        //构造
		Iterator(PNode ptr = nullptr)
		{
			_pnode = ptr;
		}
        //没有析构函数,让编译器自动生成就可以了,因为没有资源需要释放
        //返回当前iterator指向的节点的_val值
		T& operator*()
		{
			return _pnode->_val;
		}
        
        //如果_val的类型是一个结构体的话可以使用这个,这个的意思就是访问_val的成员
        
		T* operator->()
		{
			return &(_pnode->_val);
		}
        //前置++
		Self& operator++()
		{
			_pnode = _pnode->_next;
			return *this;
		}
        //后置++
		Self operator++(int)
		{
			PNode tmp = _pnode;
			_pnode = _pnode->_next;
			return tmp;
		}
		Self& operator--()
		{
			_pnode = _pnode->_prev;
			return* this;
		}
		Self operator--(int)
		{
			PNode* tmp = _pnode;
			_pnode = _pnode->_prev;
			return tmp;
		}
		bool operator!=(const Self& l)
		{
			return _pnode != l._pnode;
		}
		bool operator==(const Self& l)
		{
			return _pnode == l._pnode;
		}
	private:
		PNode _pnode;
	};

 这里将operator-> 的一些注意事项:

理解一下operator->()的本质,就是返回_val的首元素地址。

//假如T的类型是class A
class A
{

public:
    int a;
    int b;
}

//
list<A> ls = {{1,2},{2,3},{2,4}}};
list<A>::iterator it = ls.begin();
it->a; //这句代码的实现就是  it.operator->()->a; 也就是先调用operator->(),再用其返回值加上下标引用操作符访问a,可以理解为operator->()返回的是结构体或类的等可以通过下标访问操作符访问其成员的指针

注意前置++,和后置++的区别

首先,前置++,是先++后使用,返回的是该iterator的引用。

后置++,是先使用后++,所以返回的是++之前的值,所以返回值,就是++前的iterator(不是引用)。

前置--,和后置--也是类似的道理。

4.const_iterator 迭代器

注意const_iterator与iterator的区别,不是再iterator前加一个const,注意cosnt和iterator之间有一个下划线连接;而两者的真正区别就是const_iterator不允许对iterator指向的节点的元素的值进行修改

	template<class T>
	class Iterator
	{
		typedef list_node<T>* PNode;
		typedef list_node<T> Node;
		typedef Iterator<T> Self;
	public:
        //构造
		Iterator(PNode ptr = nullptr)
		{
			_pnode = ptr;
		}
        //没有析构函数,让编译器自动生成就可以了,因为没有资源需要释放
        //返回当前iterator指向的节点的_val值
		const T& operator*()
		{
			return _pnode->_val;
		}
        
        //如果_val的类型是一个结构体的话可以使用这个,这个的意思就是访问_val的成员
        
		const T* operator->()
		{
			return &(_pnode->_val);
		}
        //前置++
		const Self& operator++()
		{
			_pnode = _pnode->_next;
			return *this;
		}
        //后置++
		const Self operator++(int)
		{
			PNode tmp = _pnode;
			_pnode = _pnode->_next;
			return tmp;
		}
		const Self& operator--()
		{
			_pnode = _pnode->_prev;
			return* this;
		}
		const Self operator--(int)
		{
			PNode* tmp = _pnode;
			_pnode = _pnode->_prev;
			return tmp;
		}
		bool operator!=(const Self& l)
		{
			return _pnode != l._pnode;
		}
		bool operator==(const Self& l)
		{
			return _pnode == l._pnode;
		}
	private:
		PNode _pnode;
	};

跟上面的iterator的实现差不多就是返回值需要用const修饰,毕竟不允许修改值嘛。

5.合并iterator和const_iterator

上面的两个迭代器的实现非常类似,所以能否通过一个模板来实现呢?

注意上面两个代码的异同

iterator    const_iterator
T           const T
T*          const T*
T&          const T&
//下面两个可以根据传入的T还是const T来相应的生成。
iterator<T>  const_iterator<const T> 
iterator<T>&     const_iterator<const T>&

 

所以只需要根据前三个参数,模板就可以知道生成iterator的模板还是const_iterator的模板。

	template<class T,class Ref,class Ptr>
	class Iterator
	{
		typedef list_node<T>* PNode;
		typedef list_node<T> Node;
		typedef Iterator<T, Ref, Ptr> Self;
	public:
		Iterator(PNode ptr = nullptr)
		{
			_pnode = ptr;
		}

		T& operator*()
		{
			return _pnode->_val;
		}
		PNode operator->()
		{
			return _pnode;
		}

		Self& operator++()
		{
			_pnode = _pnode->_next;
			return *this;
		}

		Self operator++(int)
		{
			PNode tmp = _pnode;
			_pnode = _pnode->_next;
			return tmp;
		}
		Self& operator--()
		{
			_pnode = _pnode->_prev;
			return* this;
		}
		Self operator--(int)
		{
			PNode* tmp = _pnode;
			_pnode = _pnode->_prev;
			return tmp;
		}
		bool operator!=(const Self& l)
		{
			return _pnode != l._pnode;
		}
		bool operator==(const Self& l)
		{
			return _pnode == l._pnode;
		}
	private:
		list_node<T>* _pnode;
	};

实例化时:

template<class T>
class list		
{
public:
        typedef Iterator<T,T&,T*> iterator;//iteraotr迭代器
		typedef Iterator<const T, const T&, const T*> const_iterator;//const_iterator迭代器
}

完整代码。 

刷题记录: 用来调试刷题是写的代码 (gitee.com)


http://www.kler.cn/news/325091.html

相关文章:

  • navicat连接postgresql的ERROR: column datlastsysoid
  • 美图AI短片创作工具MOKI全面开放 支持生成配乐、细节修改
  • Pencils Protocol 成市场新宠,生态通证$DAPP价值几何
  • 鸿蒙HarmonyOS开发生态
  • 使用vite+react+ts+Ant Design开发后台管理项目(四)
  • 巧用枚举消除条件判断
  • ETH以太网资源学习
  • 【YashanDB知识库】yashandb执行包含带oracle dblink表的sql时性能差
  • 学习react小记
  • 独孤思维:又取关了一批副业博主,真相扎心了
  • 区块链媒体推广:15个数字解读未来-华媒舍
  • 代码随想录算法训练营day41
  • 周家庄智慧旅游小程序
  • Excel-统计日期内的个数1月到12月
  • 研究生如何利用ChatGPT帮助开展日常科研工作?
  • Linux---文件io
  • delphi制作漂亮的农历窗体(IntraWeb+Layui的完美结合)
  • 【设计模式-中介者模式】
  • EHS管理系统设备安全设施安全监控模块
  • 用manim实现有想法的Pi
  • 能力成熟度模型集成(CMMI)
  • c# 结构体反射赋值问题 结构体 反射赋值
  • 百度智能体创建:情感领域的创新力量
  • 大模型训练:K8s 环境中数千节点存储最佳实践
  • 车辆零部件检测和分割数据集-车体数据集-yolo格式-yolov5-yolov10可用
  • docker-图形化工具-portainer的使用
  • Vue $router.push打开新窗口
  • 【Linux网络】详解TCP协议(2)
  • 网站建设中常见的网站后台开发语言有哪几种,各自优缺点都是什么?
  • python和pyqt-tools安装位置