首页 > 编程语言 >C++list的模拟实现

C++list的模拟实现

时间:2024-07-05 19:30:23浏览次数:21  
标签:node Node return list C++ operator ListIterator prev 模拟

链表节点

	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());
		}

标签:node,Node,return,list,C++,operator,ListIterator,prev,模拟
From: https://blog.csdn.net/2301_80395066/article/details/140138465

相关文章

  • Linux 交叉编译(toolchain) ARM aarch64版 libc++.so 库
    前言全局说明libc++源码libc++是LLVM项目提供的一个C++标准库的实现,它是KonaKart等项目的基础。由于libc++是开源>的,因此您可以在其官方仓库中找到源代码。一、说明如果您想要阅读libc++的源代码,可以按照以下步骤进行:访问libc++的官方GitHub仓库:https://github.com/llv......
  • C++基础知识持续更新,今天来记录结构体的基本知识,包括结构体的定义和使用,结构体数组,结
    C++结构体C++基础知识持续更新,今天来记录结构体的基本知识,包括结构体的定义和使用,结构体数组,结构体指针,结构体嵌套结构体,结构体做函数参数,结构体中的const的使用场景,以及结构体的案例。1.结构体的定义和使用结构体属于用户自定义的数据类型,允许用户存储不同的数据类型。......
  • 模拟集成电路设计系列博客——9.3 采样保持电路
    模拟集成电路设计9.3采样保持电路采样保持电路是集成电路中的一个重要组件,尤其是在数据转换器中。在许多情况下,使用采样保持(在数据转换器的前端)可以大大减少由于转换器内部操作中的延迟时间略有不同而导致的误差。采样保持电路的一种最简单的实现方式如下图所示,当\(\phi_{clk}......
  • 构建LangChain应用程序的示例代码:56、如何实现一个多智能体模拟,其中没有固定的发言顺
    多智能体分散式发言人选择示例展示了如何实现一个多智能体模拟,其中没有固定的发言顺序。智能体自行决定谁来发言,通过竞价机制实现。我们将在下面的示例中展示一场虚构的总统辩论来演示这一过程。导入LangChain相关模块fromtypingimportCallable,Listimporttena......
  • 3-List
    ListList继承于CollectionList常用方法/*List接口中常用方法:增加:add(intindex,Eelement)删除:remove(intindex)remove(Objecto)修改:set(intindex,Eelement)查看:get(intindex)判断:......
  • C++基础语法篇
    一、语法1.定义变量并赋值:数据类型 变量名=值;2.宏常量定义#define会报错,提示转换:constexprauto数据类型常量名=常量值;3.定义普通(局部)常量:const 数据类型常量名=常量值;4.sizeof关键字,查询占用空间 sizeo......
  • C++ 类型转换注意事项总结
    在C++中,类型转换是编程过程中不可避免的一部分,但不当的类型转换可能会导致程序错误、数据损坏甚至程序崩溃。因此,了解类型转换的注意事项至关重要。以下是C++类型转换时需要注意的几个方面:1.区分隐式类型转换和显式类型转换隐式类型转换:由编译器自动完成,无需程序员干预。......
  • java List集合排序方式
    javaList集合排序方式1.使用直接上代码packagecom.demo;importcn.hutool.core.date.DateTime;importlombok.AllArgsConstructor;importlombok.Data;importjava.util.*;importjava.util.stream.Collectors;publicclassDemoCollectionsSortMain{public......
  • ArrayList底层结构和源码分析
    //无参构造器创建ArrayList对象//ArrayListlist=newArrayList();//断点1ArrayListlist=newArrayList(8);//断点2//添加1-10数据for(inti=0;i<=10;i++){list.add(i);}//添......
  • ArrayList和LinkedList的比较
    基本比较 底层结构增删效率改查效率ArrayList可变数组较低;数组扩容较高LinkedList双向链表较高,通过链表追加较低选择使用若改查操作多选择ArrayList增删操作多选择LinkedList通常程序中大部分操作为查询,因此通常使用ArrayList根据需求,效率优先的原则......