C++模拟实现list

list的实现最主要的点就是迭代器的实现,不能在使用原生指针,因为链表的结点并不是连续的。于是使用类来实现迭代器,具体代码如下:

namespace QBL
{
	template<class T>//结点的数据类型
	struct ListNode
	{
		ListNode(const T& x = T())//结点初始化的时候数据给默认值,默认值是数据类型的匿名对象,匿名对象执行无参构造
			:_next(nullptr)
			, _prev(nullptr)
			, _Data(x)//当结点数据类型是自定义类的时候会去执行拷贝构造,所以无需担心浅拷贝的问题
		{

		}

		ListNode* _next;
		ListNode* _prev;
		T _Data;
	};

	template<class T>
	struct ListIterator
	{//因为原生指针node* 无法直接进行类似指针++或者--或者解引用的操作,于是写一个类,专门用来控制迭代器的行为
		typedef ListNode<T> Node;
		typedef ListIterator<T> Self;

		Node* pnode;//定义的迭代器类其实还是指针,只不过我们可以重载迭代器的行为了

		ListIterator(Node* p)
			:pnode(p)
		{}

		Self& operator++()//我们定义一个迭代器对象,对象++其实就是指针指向下一个
		{
			pnode = pnode->_next;
			return *this;//返回一个迭代器,即此类
		}
		Self operator++(int)//后置++
		{
			Self tmp(*this);//因为是指针,目的就是指向同一个位置,所以浅拷贝没问题
			pnode = pnode->_next;
			return tmp;
		}

		Self& operator--()
		{
			pnode = pnode->_prev;
			return *this;
		}
		Self operator--(int)
		{
			Self tmp(*this);
			pnode = pnode->_prev;
			return tmp;
		}

		T& operator*()
		{
			return pnode->_Data;
		}
		T* operator->()
		{
			return &(pnode->_Data);
		}

		bool operator!=(Self get_pnode)
		{
			return pnode != get_pnode.pnode;
		}

		bool operator==(Self get_pnode)
		{
			return pnode == get_pnode.pnode;
		}
	};

	template<class T>
	struct ListConstIterator//重新写一个类,专门用来访问const修饰是的链表,这个类的迭代器解引用的数据无法修改
	{//const迭代器就是普通的迭代器的赋值,但是修改了解引用和->
		typedef ListNode<T> Node;
		typedef ListConstIterator<T> Self;

		Node* pnode;

		ListConstIterator(Node* p)
			:pnode(p)
		{}

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

		Self& operator--()
		{
			pnode = pnode->_prev;
			return *this;
		}
		Self operator--(int)
		{
			Self tmp(*this);
			pnode = pnode->_prev;
			return tmp;
		}

		const T& operator*()//此类的解引用无法修改结点数据
		{
			return pnode->_Data;
		}
		const T* operator->()
		{
			return &(pnode->_Data);
		}

		bool operator!=(Self get_pnode)
		{
			return pnode != get_pnode.pnode;
		}

		bool operator==(Self get_pnode)
		{
			return pnode == get_pnode.pnode;
		}
	};

	template <class T>
	class list
	{
		typedef ListNode<T> node;
	public:
		typedef ListIterator<T> iterator;
		typedef ListIterator<T> const_iterator;
		list()
		{
			_head = new node;//初始化开辟的是哨兵位
			_head->_next = _head;//哨兵位的next和prev都指向自己
			_head->_prev = _head;
			_size = 0;
		}
		/*void push_back(const T& x)
		{
			node* tmp = new node(x);
			node* tail = _head->_prev;
			tmp->_next = _head;
			tmp->_prev = tail;
			_head->_prev = tmp;
			tail->_next = tmp;
		}*/

		iterator begin()//begin和end返回的都是迭代器类型,这样才能对迭代器进行操作访问其他结点
		{
			return iterator(_head->_next);//返回匿名对象,虽然是传值返回,但是返回的是迭代器,所以没问题
		}
		iterator end()
		{
			return iterator(_head);//end是指向哨兵位的,并不是最有一个结点
		}

		const_iterator begin()const//不能使用const修饰iterator,因为const修饰的是迭代器对象,而我们需要的是结点的数据无法修改
		{//const_iterator属于一个新的类,专门用来解决const修饰的list
			return const_iterator(_head->_next);
		}
		const_iterator end()const
		{
			return const_iterator(_head);
		}

		void insert(iterator pos, const T& val)//在某个结点前面插入
		{
			node* cur = pos.pnode;
			node* tmp = new node(val);
			node* prev = cur->_prev;
			tmp->_next = cur;
			tmp->_prev = prev;
			prev->_next = tmp;
			cur->_prev = tmp;
			++_size;
		}

		iterator erase(iterator pos)//erase后,pos失效,所以返回下一个结点的迭代器
		{
			node* prev = pos.pnode->_prev;
			node* next = pos.pnode->_next;
			prev->_next = next;
			next->_prev = prev;
			delete pos.pnode;
			--_size;
			return iterator(next);
		}

		void push_back(const T& val)
		{
			insert(end(), val);
		}

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

		void pop_back()
		{
			erase(--end());
		}

		void pop_front()
		{
			erase(begin());
		}

		size_t size()const
		{
			return _size;
		}

		bool empty()
		{
			return _size == 0;
		}

	private:
		node* _head;//链表只有一个成员变量指向哨兵位
		size_t  _size;
	};
	void test1()
	{
		list<int> lt;
		lt.push_back(5);
		lt.push_back(5);
		lt.push_back(4);
		lt.push_back(3);
		lt.push_back(2);
		lt.push_back(1);
		list<int>::iterator it = lt.begin();//定义一个迭代器对象去访问链表的结点
		while(it != lt.end())
		{
			cout << *it << " ";
			++it;
		}
		cout << endl;
		lt.push_front(103);
		lt.push_front(13);
		lt.push_front(03);
		lt.pop_back();
		lt.pop_back();
		lt.pop_front();
		lt.pop_front();
		for (auto e : lt)
		{
			cout << e << " ";
		}
		cout << endl;
	}
	void test2()
	{
		struct A
		{
			int a1;
			int a2;
			A(int aa1 = 0, int aa2 = 0)
				:a1(aa1)
				,a2(aa2)
			{

			}
		};
		A A1(1, 1);
		list<A> lt;
		lt.push_back(A1);
		lt.push_back({2, 2});
		lt.push_back(A(3, 3));
		list<A>::iterator it = lt.begin();//当为模板为自定义类型的时候,解引用重载就无法使用了,因为无法解引用自定义类型
		while (it != lt.end())
		{
			cout << it->a1 << " " << it->a2 << " ";//下面一行代码和这一行一样的意思,编译器优化掉了一个->
			///cout << it.operator->()->a1 << " " << it.operator->()->a2 << " ";
			it++;
			cout << endl;
		}
		cout << endl;
	}
}

可以发现上述代码中为了解决const修饰的链表仍然可以通过迭代器修改结点的值的问题,重新写了一个类,但是这个类中只要解引用和->访问被const修饰了。其他成员函数都是一样的。于是可以通过模板解决这个冗余的问题。讲解引用和->的重载返回值改用模板参数。然后通过list中的两个宏去定义二者。这样就有了两个类,且功能和上面的代码一样。

namespace QBL
{
	template<class T>//结点的数据类型
	struct ListNode
	{
		ListNode(const T& x = T())//结点初始化的时候数据给默认值,默认值是数据类型的匿名对象,匿名对象执行无参构造
			:_next(nullptr)
			, _prev(nullptr)
			, _Data(x)//当结点数据类型是自定义类的时候会去执行拷贝构造,所以无需担心浅拷贝的问题
		{

		}

		ListNode* _next;
		ListNode* _prev;
		T _Data;
	};

	template<class T, class Ref, class Ptr>//与上面相比,只要解引用和->不一样,写成模板,让编译器生成一个带const和一个不带const的就行
	struct ListIterator
	{//因为原生指针node* 无法直接进行类似指针++或者--或者解引用的操作,于是写一个类,专门用来控制迭代器的行为
		typedef ListNode<T> Node;
		typedef ListIterator<T, Ref, Ptr> Self;

		Node* pnode;//定义的迭代器类其实还是指针,只不过我们可以重载迭代器的行为了

		ListIterator(Node* p)
			:pnode(p)
		{}

		Self& operator++()//我们定义一个迭代器对象,对象++其实就是指针指向下一个
		{
			pnode = pnode->_next;
			return *this;//返回一个迭代器,即此类
		}
		Self operator++(int)//后置++
		{
			Self tmp(*this);//因为是指针,目的就是指向同一个位置,所以浅拷贝没问题
			pnode = pnode->_next;
			return tmp;
		}

		Self& operator--()
		{
			pnode = pnode->_prev;
			return *this;
		}
		Self operator--(int)
		{
			Self tmp(*this);
			pnode = pnode->_prev;
			return tmp;
		}

		Ref operator*()
		{
			return pnode->_Data;
		}
		Ptr operator->()
		{
			return &(pnode->_Data);
		}

		bool operator!=(Self get_pnode)
		{
			return pnode != get_pnode.pnode;
		}

		bool operator==(Self get_pnode)
		{
			return pnode == get_pnode.pnode;
		}
		
	};

	template <class T>
	class list
	{
		typedef ListNode<T> node;
	public:
		typedef ListIterator<T, T&, T*> iterator;//通过定义两个不同的宏再通过模板来实现两种类
		typedef ListIterator<T, const T&, const T*> const_iterator;
		void empty_init()
		{
			_head = new node;//初始化开辟的是哨兵位
			_head->_next = _head;//哨兵位的next和prev都指向自己
			_head->_prev = _head;
			_size = 0;
		}
		list()
		{
			empty_init();
		}
		list(const list<T>& lt)//拷贝构造
		{
			empty_init();//有一个头节点以后,在进行尾插就很方便
			for (auto& e : lt)
			{
				push_back(e);
			}
		}
		void swap(list& lt)
		{
			std::swap(_head, lt._head);
			std::swap(_size, lt._size);
		}
		list<T>& operator=(list lt)
		{
			swap(lt);//因为是和临时对象交换的,交换过后出函数,函数执行析构,原来的结点也会被释放掉
			return *this;
		}
		/*void push_back(const T& x)
		{
			node* tmp = new node(x);
			node* tail = _head->_prev;
			tmp->_next = _head;
			tmp->_prev = tail;
			_head->_prev = tmp;
			tail->_next = tmp;
		}*/

		iterator begin()//begin和end返回的都是迭代器类型,这样才能对迭代器进行操作访问其他结点
		{
			return iterator(_head->_next);//返回匿名对象,虽然是传值返回,但是返回的是迭代器,所以没问题
		}
		iterator end()
		{
			return iterator(_head);//end是指向哨兵位的,并不是最有一个结点
		}

		const_iterator begin()const//不能使用const修饰iterator,因为const修饰的是迭代器对象,而我们需要的是结点的数据无法修改
		{//const_iterator属于一个新的类,专门用来解决const修饰的list
			return const_iterator(_head->_next);
		}
		const_iterator end()const
		{
			return const_iterator(_head);
		}

		void insert(iterator pos, const T& val)//在某个结点前面插入
		{
			node* cur = pos.pnode;
			node* tmp = new node(val);
			node* prev = cur->_prev;
			tmp->_next = cur;
			tmp->_prev = prev;
			prev->_next = tmp;
			cur->_prev = tmp;
			++_size;
		}

		iterator erase(iterator pos)//erase后,pos失效,所以返回下一个结点的迭代器
		{
			node* prev = pos.pnode->_prev;
			node* next = pos.pnode->_next;
			prev->_next = next;
			next->_prev = prev;
			delete pos.pnode;
			--_size;
			return iterator(next);
		}

		void push_back(const T& val)
		{
			insert(end(), val);
		}

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

		void pop_back()
		{
			erase(--end());
		}

		void pop_front()
		{
			erase(begin());
		}

		size_t size()const
		{
			return _size;
		}

		bool empty()
		{
			return _size == 0;
		}

		void clear()//没有清除头节点,只清除所有数据
		{
			iterator it = begin();
			while (it != end())
			{
				it = erase(it);//erase返回下一个位置的迭代器
			}
		}
		~list()
		{
			clear();
			delete _head;
			_head = nullptr;
		}

	private:
		node* _head;//链表只有一个成员变量指向哨兵位
		size_t  _size;
	};
	void PrintList(const list<int>& clt)
	{
		list<int>::const_iterator it = clt.begin();
		for (auto e : clt)
		{
			cout << e << " ";
		}
		cout << endl;
	}
	void test1()
	{
		list<int> lt;
		lt.push_back(5);
		lt.push_back(5);
		lt.push_back(4);
		lt.push_back(3);
		lt.push_back(2);
		lt.push_back(1);
		list<int>::iterator it = lt.begin();//定义一个迭代器对象去访问链表的结点
		while (it != lt.end())
		{
			cout << *it << " ";
			++it;
		}
		cout << endl;
		lt.push_front(103);
		lt.push_front(13);
		lt.push_front(03);
		lt.pop_back();
		lt.pop_back();
		lt.pop_front();
		lt.pop_front();
		for (auto e : lt)
		{
			cout << e << " ";
		}
		cout << endl;
	}
	void test2()
	{
		struct A
		{
			int a1;
			int a2;
			A(int aa1 = 0, int aa2 = 0)
				:a1(aa1)
				, a2(aa2)
			{

			}
		};
		A A1(1, 1);
		list<A> lt;
		lt.push_back(A1);
		lt.push_back({ 2, 2 });
		lt.push_back(A(3, 3));
		list<A>::iterator it = lt.begin();//当为模板为自定义类型的时候,解引用重载就无法使用了,因为无法解引用自定义类型
		while (it != lt.end())
		{
			cout << it->a1 << " " << it->a2 << " ";//下面一行代码和这一行一样的意思,编译器优化掉了一个->
			///cout << it.operator->()->a1 << " " << it.operator->()->a2 << " ";
			it++;
			cout << endl;
		}
		cout << endl;
	}
	void test3()
	{
		list<int> lt1;
		lt1.push_back(11);
		lt1.push_back(12);
		lt1.push_back(13);
		lt1.push_back(14);
		lt1.push_back(15);
		lt1.push_back(16);
		PrintList(lt1);
		list<int> lt2 = lt1;
		PrintList(lt2);
		list<int> lt3(lt2);
		PrintList(lt3);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值